from pyparsing import *

#------------------------------------------------------------------------------------------------------
# CLASS ASSEMBLER 
#------------------------------------------------------------------------------------------------------
class Assembler(object):
    def __init__(self, args):
      
        formaterList = FormaterList()
        formaterList.registerComponent("bin", Binary_Formater)
        formaterList.registerComponent("vhdl", VHDL_Formater)
        formaterList.registerComponent("coe", COE_Formater)
        formaterList.registerComponent("symboltable", SYMBOLTABLE_Formater)
        
        if len(args) != 4: 
            print
            print "usage: python clvpasm.py <format> <infilename> <outfilename>"
            print "   supported formats are: " + formaterList.getList()
            sys.exit(1)
        
        format = args[1]
        fileNameIn = args[2]
        fileNameOut = args[3]
            
        formater = formaterList.getFormater(format)
        
        if formater == None:
            print
            print "error: unsupported format, use one of the following: " + formaterList.getList()
            sys.exit(1)
        
        try:
            fileIn = open (fileNameIn,"r")
            programcode, symbols = Parser().parse(fileIn.readlines())
            fileIn.close()
        except IOError:
            print
            print "error: unable to open input file: " + fileNameIn
            sys.exit(1)
            
        try:
            formaterList.getFormater(format).write(programcode, symbols, fileNameOut)
            print "done"
        except IOError:
            print
            print "error: unable to write output file: " + fileNameOut
            sys.exit(1)
        
#------------------------------------------------------------------------------------------------------
# CLASS FORMATERLIST
#------------------------------------------------------------------------------------------------------
class FormaterList(object):
    def __init__(self): 
        self.components = []
  
    def getFormater(self, format):                                      
        for a in self.components:                                   
            if format.lower().lstrip().startswith(a[0].lower()):   
                return a[1]()
        
        return None;
        
    def getList(self):
        cmdlist = []
        for a in self.components:  
            cmdlist.append(a[0])
        
        return str(cmdlist)
        
    def registerComponent(self,format,component): 
        self.components.append([format,component])

#------------------------------------------------------------------------------------------------------
# CLASS VHDL_FORMATER
#------------------------------------------------------------------------------------------------------
class VHDL_Formater(object):
    def write(self, code, symbols, filename):
        
        #get last adress
        list = sorted(code.iteritems())
        list.reverse()
        end = list[0][0]
        
        f=open(filename,"w")
        
        f.write("-- ********************************************\n")
        f.write("-- * SRAM FILE GENERATED BY HiCoVec ASSEMBLER *\n")
        f.write("-- *  do not make modifications here          *\n")
        f.write("-- ********************************************\n\n")
        f.write("library ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.std_logic_unsigned.all;\n")
        f.write("entity sram is\n\tport (\n\t\tclk : in std_logic;\n\t\twe : in std_logic;\n\t\ten : in std_logic;\n")
        f.write("\t\taddr : in std_logic_vector(31 downto 0);\n\t\tdi : in std_logic_vector(31 downto 0);\n")
        f.write("\t\tdo : out std_logic_vector(31 downto 0)\n\t);\nend sram;\n")
        f.write("architecture rtl of sram is\n")
        f.write("\ttype memory_type is array(0 to " + str(end+1) + ") of std_logic_vector(31 downto 0);\n")
        f.write("\tsignal memory : memory_type := (\n")
        
        for i in range(0,end+1):
            if code.has_key(i):
                f.write('\t\t"' + code[i][0] + '", -- ' + hex(i) + ' : ' +code[i][1] +'\n')
            else:
                f.write('\t\t"00000000000000000000000000000000", -- ' + hex(i)+'\n')
        
        f.write('\t\t"00000000000000000000000000000000"'+'\n')
        f.write('\t);'+'\n')
        
        f.write("begin\n\tprocess (clk)\n\tbegin\n\t\tif clk'event and clk = '1' then\n\t\t\tif en = '1' then\n")
        f.write("\t\t\t\tif we = '1' then\n\t\t\t\t\tmemory(conv_integer(addr)) <= di;\n\t\t\t\t\tdo <= di;\n")
        f.write("\t\t\t\telse\n\t\t\t\t\tdo <= memory(conv_integer(addr));\n\t\t\t\tend if;\n\t\t\tend if;\n\t\tend if;\n")
        f.write("\tend process;\nend;\n")

        f.close()
        
        
#------------------------------------------------------------------------------------------------------
# CLASS BINARY_FORMATER
#------------------------------------------------------------------------------------------------------
class Binary_Formater(object):
    def write(self, code, symbols, filename):
        
        #get last adress
        list = sorted(code.iteritems())
        list.reverse()
        end = list[0][0]
        
        f=open(filename,"wb")
          
        for i in range(0,end+1):
            if code.has_key(i):
                value = string.atoi(code[i][0],2)
                m = string.atoi("11111111000000000000000000000000",2)
                for j in range(4):        
                    a = (value & m) >> 8 * (3-j)
                    m = m >> 8
                    f.write(chr(a))
            else:
                f.write(chr(0) + chr(0) + chr(0) + chr(0))
        f.close()
        
#------------------------------------------------------------------------------------------------------
# CLASS COE_FORMATER
#------------------------------------------------------------------------------------------------------
class COE_Formater(object):
    def write(self, code, symbols, filename):
        
        #get last adress
        list = sorted(code.iteritems())
        list.reverse()
        end = list[0][0]
        
        f=open(filename,"w")
        f.write("; COE FILE FOR XILINX CORE GENERATOR\n")
        f.write("; depth=" + str(end + 1) + ", and width=32\n")
        f.write(";\n")
        f.write("memory_initialization_radix=2;\n")
        f.write("memory_initialization_vector=\n")
        
        for i in range(0,end+1):
            if code.has_key(i):
                f.write(code[i][0] + ",\n")
            else:
                f.write("00000000000000000000000000000000,\n")
        
        f.write("00000000000000000000000000000000;\n")
        
        f.close()
        
#------------------------------------------------------------------------------------------------------
# CLASS SYMBOLTABLE_FORMATER
#------------------------------------------------------------------------------------------------------
class SYMBOLTABLE_Formater(object):
    def write(self, code, symbols,  filename):
        
        f=open(filename,"w")
        
        for sym, addr in sorted(symbols.iteritems()):
            f.write(str(addr) + ":"  + str(sym) + "\n")
        
        f.close()


#------------------------------------------------------------------------------------------------------
# CLASS INSTRUCTION
#------------------------------------------------------------------------------------------------------        
class Instruction(object):
    def __init__(self):
        self.bincode = []
        for i in range(32):
            self.bincode.append("0")
    
    def revert(self,value):
        result = ""
        for i in range(len(value),0,-1):
            result = result + value[i-1]
        return result
        
    def insert(self, start, end, value):
        for i in range (start+1, end, -1):
            self.bincode[i-1] = self.revert(value)[i-1-end]
    
    def tostring(self):
        result = ""
        for i in range(32,0, -1):
            result = result + self.bincode[i-1]
        return result
    
    def tobinary(self,n):
        b = ""
        if n == 0:
            b= "0"
        else:
            while n > 0:
                b = str(n % 2) + b
                n = n >> 1
        return b
    
    def insertImmediate(self, n):
        self.insert(15,0,self.tobinary(n).rjust(16,"0"))
    
    def insertConstant(self, n):
        self.insert(31,0,self.tobinary(n).rjust(32,"0"))
        
    def insertR(self,r):
        self.insert(11,8,self.tobinary(r).rjust(4,"0"))
        
    def insertV(self,v):
        self.insert(7,4,self.tobinary(v).rjust(4,"0"))
    
    def insertW(self,w):
        self.insert(3,0,self.tobinary(w).rjust(4,"0"))
    
    def insertVectorImmediate(self,n):
        self.insert(27,20,self.tobinary(n).rjust(8,"0"))
        
#------------------------------------------------------------------------------------------------------
# CLASS PARSER
#------------------------------------------------------------------------------------------------------
class Parser:
    def tointeger(self,s):
        if s[0] == "$":
            return string.atoi(s[1:], base = 16)
        
        if s[0] == "%":
            return string.atoi(s[1:], base = 2)
            
        if s[0] == "R":
            return string.atoi(s[1:])
        
        return string.atoi(s)
    
    def parse(self, program):
        
        #create parsed commandlist
        errorcounter = 0
        commands = []
        linenr = 0
        
        for line in program:
            linenr = linenr + 1
            line = line.strip().upper()
            
            try:
                result = LineParser().parseLine(line)
                if result.dcommand or result.vcommand or result.command or result.ccommand:
                    commands.append((result, linenr))
            
            except ParseException, err:
                print
                print "conflict in line " + str(linenr) + ":"
                print line
                print " "*err.loc + "^ " + "parse error"
                errorcounter = errorcounter + 1
        
        #create symbol table, assign adresses, detect conflicts
        symbols = {}
        program = {}
        
        address = 0
        
        for cmd, linenr in commands:
            if cmd.dcommand == "ORG":
                address = self.tointeger(cmd.address)
            
            if cmd.dcommand == "EQU":              
                if symbols.has_key(cmd.symbol):
                    print
                    print "conflict in line " + str(linenr) + ":"
                    print "=> symbol " + cmd.symbol + " has already been defined" 
                    errorcounter = errorcounter + 1
                else:
                    symbols[cmd.symbol] = self.tointeger(cmd.value)
                
            if cmd.label:
                if symbols.has_key(cmd.label[0]):
                    print
                    print "conflict in line " + str(linenr) + ":"
                    print "=> symbol " + cmd.label[0] + " has already been defined" 
                    errorcounter = errorcounter + 1
                else:
                    symbols[cmd.label[0]] = address
                
            if cmd.dcommand != "ORG" and cmd.dcommand != "EQU":
                if program.has_key(address):
                    print
                    print "conflict in line " + str(linenr) + ":"
                    print "=> memory address " + hex(address) + " is already in use" 
                    errorcounter = errorcounter + 1

                program [address] = (cmd, linenr)
                address = address + 1
        
        
        #translate into machine program
        code = {}
        
        for addr, prg in sorted(program.iteritems()):
            cmd = prg[0]
            linenr = prg[1]

            if cmd.command and cmd.vcommand and cmd.immediate:
                print
                print "conflict in line " + str(linenr) + ":"
                print "=> you can't combine " + cmd.command + " (with immediate value) and " + cmd.vcommand 
                errorcounter = errorcounter + 1
            
            immediate = 0

            if cmd.immediate:
                try:
                    if cmd.value:
                        immediate = self.tointeger(cmd.value)
                    else:
                        immediate = symbols[cmd.symbol]
                except KeyError:
                    print
                    print "conflict in line " + str(linenr) + ":"
                    print "=> symbol " + cmd.symbol + " not declared"
                    errorcounter = errorcounter + 1
                
                if immediate > 65535:
                    print
                    print "conflict in line " + str(linenr) + ":"
                    print "=> immediate value " + cmd.immediate +" (" + hex(immediate) + ") is out of range (max = 0xFFFF)"
                    errorcounter = errorcounter + 1
            
            if cmd.rvector_register:
                if self.tointeger(cmd.rvector_register) > Settings().getN()-1:
                    print
                    print "conflict in line " + str(linenr) + ":"
                    print "=> vector register (" + cmd.rvector_register + ") is out of range (R0..R"+ str(Settings().getN()-1) + ")"
                    errorcounter = errorcounter + 1
            
            if cmd.vvector_register:
                if self.tointeger(cmd.vvector_register) > Settings().getN()-1:
                    print
                    print "conflict in line " + str(linenr) + ":"
                    print "=> vector register (" + cmd.vvector_register + ") is out of range (R0..R"+ str(Settings().getN()-1) + ")"
                    errorcounter = errorcounter + 1
                    
            if cmd.wvector_register:
                if self.tointeger(cmd.wvector_register) > Settings().getN()-1:
                    print
                    print "conflict in line " + str(linenr) + ":"
                    print "=> vector register (" + cmd.wvector_register + ") is out of range (R0..R"+ str(Settings().getN()-1) + ")"
                    errorcounter = errorcounter + 1
                    
            
            i = Instruction()
            register = {"0":"00","A":"01","X":"10","Y":"11"}
            wordlength = {"B":"00","W":"01","DW":"10","QW":"11"}
            
            alucommand = False
            jumpcommand = False
            valucommand = False
            immediate_possible = True
            
            #directive commands
            if cmd.dcommand == "DC":
                i.insertConstant(self.tointeger(cmd.address))
            
            #scalar commands
            if cmd.command == "ADD":    
                alucommand = True
                i.insert(29,26,"0000") 
            
            if cmd.command == "ADC":    
                alucommand = True
                i.insert(29,26,"0001")
            
            if cmd.command == "SUB":    
                alucommand = True
                i.insert(29,26,"0010")
            
            if cmd.command == "SBC":    
                alucommand = True
                i.insert(29,26,"0011")
            
            if cmd.command == "AND":    
                alucommand = True
                i.insert(29,26,"1000")
            
            if cmd.command == "OR":    
                alucommand = True
                i.insert(29,26,"1001")
                
            if cmd.command == "XOR":    
                alucommand = True
                i.insert(29,26,"1010")
                
            if cmd.command == "MUL":    
                alucommand = True
                i.insert(29,26,"1011") 
                
            if cmd.command == "INC":    
                alucommand = True
                i.insert(29,26,"0100")
                
            if cmd.command == "DEC":    
                alucommand = True
                i.insert(29,26,"0110")

            if cmd.command == "LSL":    
                alucommand = True
                i.insert(29,26,"1100") 
                
            if cmd.command == "LSR":    
                alucommand = True
                i.insert(29,26,"1110") 
            
            if cmd.command == "ROL":    
                alucommand = True
                i.insert(29,26,"1101") 
                
            if cmd.command == "ROR":    
                alucommand = True
                i.insert(29,26,"1111") 
            
            if cmd.command == "LD":
                i.insert(31,28,"1000")
                i.insert(25,24,register[cmd.dregister])
                i.insert(23,22,register[cmd.sregister])
                immediate_possible = True
                
            if cmd.command == "ST":
                i.insert(31,28,"1010")
                i.insert(23,22,register[cmd.sregister])
                immediate_possible = True
            
            if cmd.command == "HALT":
                i.insert(31,27,"00101")            
            
            if cmd.command == "NOP":
                i.insert(31,29,"000")
            
            if cmd.command == "JMP":
                i.insert(31,24,"00100000")
                jumpcommand = True
                
            if cmd.command == "JAL":
                i.insert(31,26,"001000")
                i.insert(25,24,register[cmd.dregister])
                jumpcommand = True
            
            if cmd.command == "JNC":
                i.insert(31,24,"00110000")
                jumpcommand = True
            
            if cmd.command == "JC":
                i.insert(31,24,"00110100")
                jumpcommand = True
                
            if cmd.command == "JNZ":
                i.insert(31,24,"00111000")
                jumpcommand = True
            
            if cmd.command == "JZ":
                i.insert(31,24,"00111100")
                jumpcommand = True

            if cmd.command == "CLC":
                i.insert(31,26,"110000")
                i.insert(23,20,"0100")
            
            if cmd.command == "CLZ":
                i.insert(31,26,"110000")
                i.insert(23,20,"1000")
                
            if cmd.command == "SEC":
                i.insert(31,26,"110000")
                i.insert(23,20,"0101")
            
            if cmd.command == "SEZ":
                i.insert(31,26,"110000")
                i.insert(23,20,"1010")
                
            #common parts of scalar commands
            if alucommand == True:   
                i.insert(31,30,"01");
                i.insert(25,24,register[cmd.dregister])
                i.insert(23,22,register[cmd.sregister])
                immediate_possible = True
            
            if jumpcommand == True:
                i.insert(23,22,register[cmd.sregister])
                immediate_possible = True
            
            if immediate_possible == True:
                if(cmd.immediate):
                    i.insert(21,20,"00")
                    i.insert(19,17,"000")
                    i.insertImmediate(immediate)
                else:
                    if cmd.tregister:
                        i.insert(21,20,register[cmd.tregister])
            
            #vector commands
            if cmd.vcommand == "VADD":
                i.insert(15,12,"0000")
                valucommand = True
                
            if cmd.vcommand == "VSUB":
                i.insert(15,12,"0010")
                valucommand = True
            
            if cmd.vcommand == "VAND":
                i.insert(15,12,"1000")
                valucommand = True
                
            if cmd.vcommand == "VOR":
                i.insert(15,12,"1001")
                valucommand = True
            
            if cmd.vcommand == "VMUL":
                i.insert(15,12,"1011")
                valucommand = True
            
            if cmd.vcommand == "VXOR":
                i.insert(15,12,"1010")
                valucommand = True
            
            if cmd.vcommand == "VLSL":
                i.insert(15,12,"1100")
                valucommand = True
            
            if cmd.vcommand == "VLSR":
                i.insert(15,12,"1110")
                valucommand = True
            
            if cmd.vcommand == "VNOP":
                i.insert(19,17,"000")
            
            if cmd.vcommand == "VMOL":
                i.insert(19,17,"001")
                i.insert(15,12,"1000")
                i.insertR(self.tointeger(cmd.rvector_register))
                i.insertV(self.tointeger(cmd.vvector_register))
            
            if cmd.vcommand == "VMOR":
                i.insert(19,17,"001")
                i.insert(15,12,"1100")
                i.insertR(self.tointeger(cmd.rvector_register))
                i.insertV(self.tointeger(cmd.vvector_register))
            
            if cmd.vcommand == "VMOV":
                i.insert(19,17,"001")
                
                if cmd.rvector_register and cmd.vvector_register: #vmov r,v
                    i.insert(15,12,"0001")
                    i.insertR(self.tointeger(cmd.rvector_register))
                    i.insertV(self.tointeger(cmd.vvector_register))
                
                if cmd.immediate:
                    if immediate > 255:
                        print
                        print "conflict in line " + str(linenr) + ":"
                        print "=> immediate value " + cmd.immediate +" (" + hex(immediate) + ") is out of range (max = 0xFF)"
                        errorcounter = errorcounter + 1
                    else:
                        if cmd.rvector_register: #vmov r, r<n>
                            i.insertVectorImmediate(immediate)
                            i.insert(15,12,"0010")
                            i.insertR(self.tointeger(cmd.rvector_register))
                        
                        if cmd.vvector_register: #vmov r<n>,r
                            i.insertVectorImmediate(immediate)
                            i.insert(15,12,"0011")
                            i.insertV(self.tointeger(cmd.vvector_register))
                
            #common parts of vector commands
            if valucommand == True:
                i.insert(19,18,"01")
                i.insert(17,16,wordlength[cmd.width])
                i.insertR(self.tointeger(cmd.rvector_register))
                i.insertV(self.tointeger(cmd.vvector_register))
                
                if cmd.wvector_register:
                    i.insertW(self.tointeger(cmd.wvector_register))
            
            #cooperative commands
            if cmd.ccommand == "VLD":
                i.insert(31,28,"1001")
                i.insert(23,22,register[cmd.sregister])
                i.insert(21,20,register[cmd.tregister])
                i.insert(19,18,"10")
                i.insert(15,12,"0010")
                i.insertR(self.tointeger(cmd.rvector_register))
            
            if cmd.ccommand == "VST":
                i.insert(31,26,"101100")
                i.insert(23,22,register[cmd.sregister])
                i.insert(21,20,register[cmd.tregister])
                i.insert(19,18,"10")
                i.insert(15,12,"0011")
                i.insertV(self.tointeger(cmd.vvector_register))
            
            if cmd.ccommand == "MOV":
                if cmd.rvector_register and cmd.tregister and cmd.sregister:    #mov r(t),s
                    i.insert(31,26,"101110")
                    i.insert(23,22,register[cmd.sregister])
                    i.insert(21,20,register[cmd.tregister])
                    i.insert(19,18,"10")
                    i.insert(15,12,"0100")
                    i.insertR(self.tointeger(cmd.rvector_register))
                    
                if cmd.vvector_register and cmd.tregister and cmd.dregister:    #mov d,v(t)
                    i.insert(31,26,"101111")
                    i.insert(25,24,register[cmd.dregister])
                    i.insert(21,20,register[cmd.tregister])
                    i.insert(19,18,"10")
                    i.insert(15,12,"0101")
                    i.insertV(self.tointeger(cmd.vvector_register))
            
            if cmd.ccommand == "MOVA":
                    i.insert(31,26,"101101")
                    i.insert(23,22,register[cmd.sregister])
                    i.insert(19,18,"10")
                    i.insert(15,12,"0110")
                    i.insertR(self.tointeger(cmd.rvector_register))
            
            if cmd.ccommand == "VSHUF":
                i.insert(31,29,"000")
                i.insert(19,18,"11")
                i.insert(17,16,cmd.perm[0:2])
                i.insert(15,12,cmd.perm[2:6])
                i.insert(27,20,cmd.perm[6:14])
                i.insertR(self.tointeger(cmd.rvector_register))
                i.insertV(self.tointeger(cmd.vvector_register))
                i.insertW(self.tointeger(cmd.wvector_register))
                
            code [addr] = (i.tostring(), string.join(cmd))

        if errorcounter > 0:
            print 
            print str(errorcounter) + " error(s) found => output has not been written"
            sys.exit(1)
        else:
            return code, symbols

#------------------------------------------------------------------------------------------------------
# CLASS LINEPARSER
#------------------------------------------------------------------------------------------------------    
class LineParser:
    def parseLine(self,line):
        
        expression = Forward()
        
        dec_value = Word("0123456789", min=1)
        hex_value = Word("$","ABCDEF0123456789", min=2)
        bin_value = Word("%","10", min=2)
        
        value = (dec_value ^ hex_value ^ bin_value).setResultsName("value")
        ident = Word( alphas, alphanums + "_" ).setResultsName("symbol")
        
        immediate = (value ^ ident).setResultsName("immediate")
        perm = Word("10", min=14, max=14).setResultsName("perm")
        
        length = (Literal("B") ^ Literal("W") ^ Literal("DW") ^ Literal("QW")).setResultsName("width")
        mult_length = (Literal("B") ^ Literal("W")).setResultsName("width")
        
        width = ("." + length)
        mult_width = ("." + mult_length)
        
        label = (ident + ":").setResultsName("label")
        
        comment = ( ";" + restOfLine).setResultsName("comment")
                
        dregister = (Literal("A") ^ Literal("X") ^ Literal("Y") ^ Literal("0")).setResultsName("dregister")
        sregister = (Literal("A") ^ Literal("X") ^ Literal("Y") ^ Literal("0")).setResultsName("sregister")
        tregister = (Literal("A") ^ Literal("X") ^ Literal("Y")).setResultsName("tregister")
        akku = Literal("A")
        
        rvector_register = Word("R","0123456789",min=2).setResultsName("rvector_register")
        vvector_register = Word("R","0123456789",min=2).setResultsName("vvector_register")
        wvector_register = Word("R","0123456789",min=2).setResultsName("wvector_register")
        
        
        directive_cmd_keyword_1 = (Keyword("ORG") ^ Keyword("DC")).setResultsName("dcommand")
        directive_cmd_keyword_2 = (Keyword("EQU")).setResultsName("dcommand")
        
        directive_cmd_1 = directive_cmd_keyword_1 + value.setResultsName("address")
        directive_cmd_2 = directive_cmd_keyword_2 + ident + value
        
        directive_cmd = (directive_cmd_1 ^ directive_cmd_2)
        
        alu_cmd_keyword_1 = (Keyword("INC") ^ Keyword("DEC") ^ Keyword("LSL") ^ Keyword("LSR") ^ Keyword("ROL") \
                            ^ Keyword("ROR")).setResultsName("command")
                            
        alu_cmd_keyword_2 = (Keyword("ADD") ^ Keyword("ADC") ^ Keyword("SUB") ^ Keyword("SBC") ^ Keyword("AND") \
                            ^ Keyword("OR") ^ Keyword("XOR") ^ Keyword("MUL")).setResultsName("command")
        
                
        alu_cmd_1 = alu_cmd_keyword_1 + dregister + "," + sregister
        alu_cmd_2 = alu_cmd_keyword_2 + dregister + "," + sregister + "," + (tregister ^ immediate)
        alu_cmd = (alu_cmd_1 ^ alu_cmd_2)
        
        jmp_cmd_keyword_1 = (Keyword("JMP") ^ Keyword("JNC") ^ Keyword("JC") ^ Keyword("JNZ") ^ Keyword("JZ")) \
                            .setResultsName("command")
        jmp_cmd_keyword_2 = Keyword("JAL").setResultsName("command")
        
        jmp_cmd_1 = jmp_cmd_keyword_1 + Optional("[") + sregister + "+" + (tregister ^ immediate) + Optional("]")
        jmp_cmd_2 = jmp_cmd_keyword_2 +  dregister + "," + Optional("[") + sregister + "+" + (tregister ^ immediate) + Optional("]")
        jmp_cmd = (jmp_cmd_1 ^ jmp_cmd_2)
        
        inherent_cmd_keyword = (Keyword ("HALT") ^ Keyword ("NOP") ^ Keyword ("CLC") ^ Keyword ("CLZ") ^ Keyword ("SEC") \
                               ^ Keyword ("SEZ")).setResultsName("command")
                                
        inherent_cmd = inherent_cmd_keyword
        
        load_cmd_keyword = Keyword("LD").setResultsName("command")
        load_cmd = load_cmd_keyword  + dregister + "," + Optional("[") + sregister + "+" + (tregister ^ immediate) + Optional("]")
        
        store_cmd_keyword = Keyword("ST").setResultsName("command")
        store_cmd = store_cmd_keyword + Optional("[") + sregister + "+" + (tregister ^ immediate) + Optional("]") +"," + akku
        
        scalar_command = (alu_cmd ^ jmp_cmd ^ inherent_cmd ^ load_cmd ^ store_cmd)
        
        mov_cmd_keyword = Keyword("MOV").setResultsName("ccommand")
        mov_cmd_1 = mov_cmd_keyword + rvector_register + "(" + tregister + ")" + "," + sregister
        mov_cmd_2 = mov_cmd_keyword + dregister + "," + vvector_register + "(" + tregister + ")"
        mov_cmd = (mov_cmd_1 ^ mov_cmd_2)
        
        vld_cmd_keyword = Keyword("VLD").setResultsName("ccommand")
        vld_cmd = vld_cmd_keyword + rvector_register + "," + Optional("[") +  sregister + "+" + tregister + Optional("]")
        
        vst_cmd_keyword = Keyword("VST").setResultsName("ccommand")
        vst_cmd = vst_cmd_keyword + Optional("[") + sregister + "+" + tregister + Optional("]") + "," + vvector_register
        
        shuffle_cmd_keyword = Keyword("VSHUF").setResultsName("ccommand")
        shuffle_cmd = shuffle_cmd_keyword + rvector_register + "," + vvector_register + "," + wvector_register + "," + perm
        
        mova_cmd_keyword = Keyword("MOVA").setResultsName("ccommand")
        mova_cmd = mova_cmd_keyword + rvector_register + "," + sregister
        
        coop_command = (mov_cmd ^ vld_cmd ^ vst_cmd ^ shuffle_cmd ^ mova_cmd)
        
        valu_cmd_keyword_1 = (Keyword("VADD") ^ Keyword("VSUB") ^ Keyword("VAND") ^ Keyword("VOR") ^ Keyword("VXOR")) \
                                 .setResultsName("vcommand")
                                
        valu_cmd_keyword_2 = (Keyword("VLSL") ^ Keyword("VLSR")).setResultsName("vcommand")
        
        valu_cmd_keyword_3 = Keyword("VMUL").setResultsName("vcommand")
        
        valu_cmd_1 = valu_cmd_keyword_1 + width +  rvector_register + "," + vvector_register + "," + wvector_register
        valu_cmd_2 = valu_cmd_keyword_2 + width + rvector_register + "," + vvector_register 
        valu_cmd_3 = valu_cmd_keyword_3 + mult_width +  rvector_register + "," + vvector_register + "," + wvector_register
        valu_cmd = (valu_cmd_1 ^ valu_cmd_2 ^ valu_cmd_3)
        
        vnop_cmd_keyword = Keyword("VNOP").setResultsName("vcommand")
        vnop_cmd = vnop_cmd_keyword
        
        vmov_cmd_keyword = Keyword("VMOV").setResultsName("vcommand")
        vmov_cmd_1 = vmov_cmd_keyword + rvector_register + "," + vvector_register
        vmov_cmd_2 = vmov_cmd_keyword + rvector_register + "," + "R" + "<" + immediate + ">"
        vmov_cmd_3 = vmov_cmd_keyword + "R" + "<" + immediate + ">" + "," + vvector_register
        vmov_cmd = (vmov_cmd_1 ^ vmov_cmd_2 ^ vmov_cmd_3)
        
        vmolr_cmd_keyword = (Keyword("VMOL") ^ Keyword("VMOR")).setResultsName("vcommand")
        vmolr_cmd = vmolr_cmd_keyword + rvector_register + "," + vvector_register
        
        vector_command = (valu_cmd ^ vnop_cmd ^ vmov_cmd ^ vmolr_cmd)
        
        command = ((directive_cmd ^ scalar_command ^ coop_command ^ vector_command) \
                  ^ (scalar_command + "|" + vector_command )\
                  ^ (vector_command + "|" + scalar_command ))
        
        
        expression << (Optional((Optional(label) + command)) + Optional(comment) + lineEnd)
        result = expression.parseString(line)
        return result

#------------------------------------------------------------------------------------------------------
# CLASS SETTINGS
#------------------------------------------------------------------------------------------------------            
class Settings(object):
    def getN(self):
        return 16
    
    def getK(self):
        return 16

#------------------------------------------------------------------------------------------------------
# MAIN PROGRAM
#------------------------------------------------------------------------------------------------------        
if __name__ == '__main__':
    Assembler(sys.argv)       

    
