def remove_from_history(self, addr, tx_hash, tx_pos):
                    
        txi = (tx_hash + int_to_hex(tx_pos, 4)).decode('hex')

        if addr is None:
            try:
                addr = self.batch_txio[txi]
            except:
                raise BaseException(tx_hash, tx_pos)
        
        serialized_hist = self.batch_list[addr]

        l = len(serialized_hist)/40
        for i in range(l):
            item = serialized_hist[40*i:40*(i+1)]
            if item[0:36] == txi:
                height = int( rev_hex( item[36:40].encode('hex') ), 16 )
                serialized_hist = serialized_hist[0:40*i] + serialized_hist[40*(i+1):]
                break
        else:
            hist = self.deserialize(serialized_hist)
            raise BaseException("prevout not found", addr, hist, tx_hash, tx_pos)

        self.batch_list[addr] = serialized_hist
        return height, addr
    def memorypool_update(self):

        mempool_hashes = self.bitcoind('getrawmempool')

        for tx_hash in mempool_hashes:
            if tx_hash in self.mempool_hashes: continue

            tx = self.get_mempool_transaction(tx_hash)
            if not tx: continue

            for x in tx.get('inputs'):
                txi = (x.get('prevout_hash') + int_to_hex(x.get('prevout_n'), 4)).decode('hex')
                try:
                    h160 = self.db.Get(txi)
                    addr = hash_160_to_bc_address(h160)
                except:
                    continue
                l = self.mempool_addresses.get(tx_hash, [])
                if addr not in l: 
                    l.append( addr )
                    self.mempool_addresses[tx_hash] = l

            for x in tx.get('outputs'):
                addr = x.get('address')
                l = self.mempool_addresses.get(tx_hash, [])
                if addr not in l: 
                    l.append( addr )
                    self.mempool_addresses[tx_hash] = l

            self.mempool_hashes.append(tx_hash)

        # remove older entries from mempool_hashes
        self.mempool_hashes = mempool_hashes

        # remove deprecated entries from mempool_addresses
        for tx_hash, addresses in self.mempool_addresses.items():
            if tx_hash not in self.mempool_hashes:
                self.mempool_addresses.pop(tx_hash)

        # rebuild histories
        new_mempool_hist = {}
        for tx_hash, addresses in self.mempool_addresses.items():
            for addr in addresses:
                h = new_mempool_hist.get(addr, [])
                if tx_hash not in h: 
                    h.append( tx_hash )
                new_mempool_hist[addr] = h

        for addr in new_mempool_hist.keys():
            if addr in self.mempool_hist.keys():
                if self.mempool_hist[addr] != new_mempool_hist[addr]: 
                    self.invalidate_cache(addr)
            else:
                self.invalidate_cache(addr)

        with self.mempool_lock:
            self.mempool_hist = new_mempool_hist
    def add_to_history(self, addr, tx_hash, tx_pos, tx_height):

        # keep it sorted
        s = (tx_hash + int_to_hex(tx_pos, 4) + int_to_hex(tx_height, 4)).decode('hex')

        serialized_hist = self.batch_list[addr] 

        l = len(serialized_hist)/40
        for i in range(l-1, -1, -1):
            item = serialized_hist[40*i:40*(i+1)]
            item_height = int( rev_hex( item[36:40].encode('hex') ), 16 )
            if item_height < tx_height:
                serialized_hist = serialized_hist[0:40*(i+1)] + s + serialized_hist[40*(i+1):]
                break
        else:
            serialized_hist = s + serialized_hist

        self.batch_list[addr] = serialized_hist

        # backlink
        txo = (tx_hash + int_to_hex(tx_pos, 4)).decode('hex')
        self.batch_txio[txo] = addr
 def serialize(self, h):
     s = ''
     for txid, txpos, height in h:
         s += txid + int_to_hex(txpos, 4) + int_to_hex(height, 4)
     return s.decode('hex')
    def import_block(self, block, block_hash, block_height, sync, revert=False):

        self.batch_list = {}  # address -> history
        self.batch_txio = {}  # transaction i/o -> address

        block_inputs = []
        block_outputs = []
        addr_to_read = []

        # deserialize transactions
        t0 = time.time()
        tx_hashes, txdict = self.deserialize_block(block)

        t00 = time.time()


        if not revert:
            # read addresses of tx inputs
            for tx in txdict.values():
                for x in tx.get('inputs'):
                    txi = (x.get('prevout_hash') + int_to_hex(x.get('prevout_n'), 4)).decode('hex')
                    block_inputs.append(txi)

            block_inputs.sort()
            for txi in block_inputs:
                try:
                    addr = self.db.Get(txi)
                except:
                    # the input could come from the same block
                    continue
                self.batch_txio[txi] = addr
                addr_to_read.append(addr)

        else:
            for txid, tx in txdict.items():
                for x in tx.get('outputs'):
                    txo = (txid + int_to_hex(x.get('index'), 4)).decode('hex')
                    block_outputs.append(txo)
            
        # read histories of addresses
        for txid, tx in txdict.items():
            for x in tx.get('outputs'):
                hash_160 = bc_address_to_hash_160(x.get('address'))
                addr_to_read.append(hash_160)

        addr_to_read.sort()
        for addr in addr_to_read:
            try:
                self.batch_list[addr] = self.db.Get(addr)
            except: 
                self.batch_list[addr] = ''


        if revert: 
            undo_info = self.get_undo_info(block_height)
            # print "undo", block_height, undo_info
        else: undo_info = {}

        # process
        t1 = time.time()

        if revert: tx_hashes = tx_hashes[::-1]
        for txid in tx_hashes: # must be ordered
            tx = txdict[txid]
            if not revert:

                undo = []
                for x in tx.get('inputs'):
                    prevout_height, prevout_addr = self.remove_from_history( None, x.get('prevout_hash'), x.get('prevout_n'))
                    undo.append( (prevout_height, prevout_addr) )
                undo_info[txid] = undo

                for x in tx.get('outputs'):
                    hash_160 = bc_address_to_hash_160(x.get('address'))
                    self.add_to_history( hash_160, txid, x.get('index'), block_height)
                    
            else:
                for x in tx.get('outputs'):
                    hash_160 = bc_address_to_hash_160(x.get('address'))
                    self.remove_from_history( hash_160, txid, x.get('index'))

                i = 0
                for x in tx.get('inputs'):
                    prevout_height, prevout_addr = undo_info.get(txid)[i]
                    i += 1

                    # read the history into batch list
                    if self.batch_list.get(prevout_addr) is None:
                        self.batch_list[prevout_addr] = self.db.Get(prevout_addr)

                    # re-add them to the history
                    self.add_to_history( prevout_addr, x.get('prevout_hash'), x.get('prevout_n'), prevout_height)
                    # print_log( "new hist for", hash_160_to_bc_address(prevout_addr), self.deserialize(self.batch_list[prevout_addr]) )

        # write
        max_len = 0
        max_addr = ''
        t2 = time.time()

        batch = leveldb.WriteBatch()
        for addr, serialized_hist in self.batch_list.items():
            batch.Put(addr, serialized_hist)
            l = len(serialized_hist)
            if l > max_len:
                max_len = l
                max_addr = addr

        if not revert:
            # add new created outputs
            for txio, addr in self.batch_txio.items():
                batch.Put(txio, addr)
            # delete spent inputs
            for txi in block_inputs:
                batch.Delete(txi)
            # add undo info 
            self.write_undo_info(batch, block_height, undo_info)
        else:
            # restore spent inputs
            for txio, addr in self.batch_txio.items():
                batch.Put(txio, addr)
            # delete spent outputs
            for txo in block_outputs:
                batch.Delete(txo)


        # add the max
        batch.Put('height', self.serialize( [(block_hash, block_height, 0)] ) )

        # actual write
        self.db.Write(batch, sync = sync)

        t3 = time.time()
        if t3 - t0 > 10 and not sync: 
            print_log("block", block_height, 
                      "parse:%0.2f "%(t00 - t0), 
                      "read:%0.2f "%(t1 - t00), 
                      "proc:%.2f "%(t2-t1), 
                      "write:%.2f "%(t3-t2), 
                      "max:", max_len, hash_160_to_bc_address(max_addr))

        for h160 in self.batch_list.keys(): 
            addr = hash_160_to_bc_address(h160)
            self.invalidate_cache(addr)
Пример #6
0
def validate_and_make_hexfile(file_asm, lines, num_errors):
    hex_file_str = ''
    extra_line_for_raw_hex = 0

    # for line in lines:
    for line_idx, line in enumerate(lines):
        first_comment_idx = line.find(COMMENT_SYMBOL)

        if first_comment_idx == -1:
            comment = ''
            code = line
        else:
            comment = line[first_comment_idx + 1:]
            code = line[:first_comment_idx]

        # args in code
        code_split = code.split(' ')

        # filter \t and ' '
        while '' in code_split:
            code_split.remove('')
        for idx in range(len(code_split)):
            code_split[idx] = code_split[idx].replace('\t', '')

        if len(code_split) > 0:
            opcode = code_split[0]
            args = code_split[1:]

            word0_first_half = '0000'
            word0_second_half = '0000'
            word1 = '00000000'

            valid_opcode = False

            # raw data
            if re.match(util.REGEX_HEX, opcode):
                valid_opcode = False
                if len(args) > 0:
                    msg = 'invalid hexcode'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

                opcode_int = util.hex_to_int(opcode)
                opcode_hex = util.int_to_hex(opcode_int)

                hex_file_str += opcode_hex.zfill(8)
                hex_file_str += '\n'

            # valid opcode
            elif opcode not in valid_opcodes_keywords:
                msg = f'invalid opcode'
                num_errors = error_msg(file_asm, line_idx, line, num_errors,
                                       msg)

            elif opcode == 'GOTO':
                valid_opcode = True
                if len(args) < 1:
                    msg = 'missing argument'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

                # GOTO LABEL
                elif re.match(util.REGEX_LABEL, args[0]):
                    opcode_val = util.opcode_lookup_dict['GOTO']

                    if args[0] not in LABELS_TO_PC.keys():
                        msg = 'unknown label'
                        num_errors = error_msg(file_asm, line_idx, line,
                                               num_errors, msg)
                    else:
                        word1 = util.int_to_hex(LABELS_TO_PC[args[0]]).zfill(8)
                        word0_second_half = opcode_val.zfill(4)

                # GOTO i
                elif re.match(util.REGEX_INT, args[0]):
                    opcode_val = util.opcode_lookup_dict['GOTO']
                    word1 = util.int_to_hex(args[0]).zfill(8)
                    word0_second_half = opcode_val.zfill(4)

                # GOTO R[i]
                elif re.match(util.REGEX_LD_R_ONE, args[0]):
                    opcode_val = util.opcode_lookup_dict['GOTO R[i]']
                    word1 = util.int_to_hex(args[0][2:-1]).zfill(8)
                    word0_second_half = opcode_val.zfill(4)

            elif opcode == 'LD':
                # Validate
                if len(args) < 2:
                    msg = f'requires 2 or more arguments after {opcode}'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

                # LD ARRAY R[X] R[Y] W H (X,Y must be <= 255)
                elif re.match(util.REGEX_ARRAY_LD, ' '.join(args)):
                    valid_opcode = True
                    opcode_val = util.opcode_lookup_dict['LD ARRAY TO VRAM']

                    all_args = re.findall(util.REGEX_ARRAY_LD, ' '.join(args))

                    label = all_args[0][0]
                    x_sprite = all_args[0][1]
                    y_sprite = all_args[0][2]
                    width_sprite = all_args[0][3]
                    height_sprite = all_args[0][4]

                    if label not in LABELS_TO_PC.keys():
                        msg = 'unknown label'
                        num_errors = error_msg(file_asm, line_idx, line,
                                               num_errors, msg)

                    label_idx = util.int_to_hex(LABELS_TO_PC[label]).zfill(4)
                    x_sprite = util.int_to_hex(x_sprite).zfill(2)
                    y_sprite = util.int_to_hex(y_sprite).zfill(2)
                    width_sprite = util.int_to_hex(width_sprite).zfill(2)
                    height_sprite = util.int_to_hex(height_sprite).zfill(2)

                    word0_first_half = label_idx
                    word0_second_half = opcode_val.zfill(4)
                    word1 = x_sprite + y_sprite + width_sprite + height_sprite

                    hex_file_str = write_two_lines_to_hexfile(
                        word0_first_half, word0_second_half, word1,
                        hex_file_str)

                # LD R[i] ARRAY  (load PC of ARRAY to R[i])
                elif re.match(util.REGEX_LD_LABEL_PC, ' '.join(args)):
                    valid_opcode = True
                    opcode_val = util.opcode_lookup_dict[
                        'LD ARRAY PC TO REGISTER']
                    word0_second_half = opcode_val.zfill(4)

                    # parse out args
                    all_args = re.findall(util.REGEX_LD_LABEL_PC,
                                          ' '.join(args))
                    ram_index = all_args[0][0]
                    label = all_args[0][1]

                    if label not in LABELS_TO_PC.keys():
                        msg = 'unknown label'
                        num_errors = error_msg(file_asm, line_idx, line,
                                               num_errors, msg)

                    label_idx = util.int_to_hex(LABELS_TO_PC[label]).zfill(4)

                    word0_first_half = label_idx
                    word1 = '0000' + util.int_to_hex(ram_index).zfill(4)

                    hex_file_str = write_two_lines_to_hexfile(
                        word0_first_half, word0_second_half, word1,
                        hex_file_str)

                # LD R[U] R[i] R[j] R[k] R[k] (i,j,k,l must be <= 255)
                elif re.match(util.REGEX_REGISTER_ONLY_ARRAY_LD,
                              ' '.join(args)):
                    valid_opcode = True
                    opcode_val = util.opcode_lookup_dict[
                        'LD REGISTERS TO VRAM']

                    all_args = re.findall(util.REGEX_REGISTER_ONLY_ARRAY_LD,
                                          ' '.join(args))

                    UVYZ = all_args[0][0]
                    x_sprite = all_args[0][1]
                    y_sprite = all_args[0][2]
                    width_sprite = all_args[0][3]
                    height_sprite = all_args[0][4]

                    UVYZ_digit = util.UVYZ_to_hex_digit[str(UVYZ)]
                    x_sprite = util.int_to_hex(x_sprite).zfill(2)
                    y_sprite = util.int_to_hex(y_sprite).zfill(2)
                    width_sprite = util.int_to_hex(width_sprite).zfill(2)
                    height_sprite = util.int_to_hex(height_sprite).zfill(2)

                    word0_first_half = UVYZ_digit + '000'
                    word0_second_half = opcode_val.zfill(4)
                    word1 = x_sprite + y_sprite + width_sprite + height_sprite

                    hex_file_str = write_two_lines_to_hexfile(
                        word0_first_half, word0_second_half, word1,
                        hex_file_str)

                # LD R[U] R[vram_idx] R[k] R[k] (k,l must be <= 255)
                elif re.match(util.REGEX_REGISTER_ONLY_VRAM_IDX_ARRAY_LD,
                              ' '.join(args)):
                    valid_opcode = True
                    opcode_val = util.opcode_lookup_dict[
                        'LD REGISTERS TO VRAM W VRAM INDEX']

                    all_args = re.findall(
                        util.REGEX_REGISTER_ONLY_VRAM_IDX_ARRAY_LD,
                        ' '.join(args))

                    UVYZ = all_args[0][0]
                    idx_to_vram_idx = all_args[0][1]
                    width_sprite = all_args[0][2]
                    height_sprite = all_args[0][3]

                    UVYZ_digit = util.UVYZ_to_hex_digit[str(UVYZ)]
                    idx_to_vram_idx = util.int_to_hex(idx_to_vram_idx).zfill(4)
                    width_sprite = util.int_to_hex(width_sprite).zfill(2)
                    height_sprite = util.int_to_hex(height_sprite).zfill(2)

                    word0_first_half = UVYZ_digit + '000'
                    word0_second_half = opcode_val.zfill(4)
                    word1 = idx_to_vram_idx + width_sprite + height_sprite

                    hex_file_str = write_two_lines_to_hexfile(
                        word0_first_half, word0_second_half, word1,
                        hex_file_str)

                elif re.match(util.REGEX_LD_R_ONE, args[0]):
                    valid_opcode = True

                    # LD R[i] R[j]
                    if re.match(util.REGEX_LD_R_ONE, args[1]):
                        opcode_val = util.opcode_lookup_dict[
                            'REGISTER TO REGISTER LOAD']
                        word1 = util.int_to_hex(args[1][2:-1]).zfill(8)

                    # LD R[i] j
                    elif re.match(r'\d+', args[1]) or re.match(
                            util.REGEX_HEX, args[1]):
                        opcode_val = util.opcode_lookup_dict['DIRECT LOAD']
                        word1 = util.int_to_hex(args[1]).zfill(8)

                    # LD R[i] R[U]
                    elif re.match(util.REGEX_UV_ONE,
                                  args[1]) and len(args) == 2:
                        opcode_val = util.opcode_lookup_dict['LD R[i] R[U]']

                        letters_arg0 = re.findall(util.REGEX_UV_ONE, args[1])
                        i = util.UVYZ_to_hex_digit[str(letters_arg0[0])]
                        word1 = i + '0000000'

                    word0_first_half = util.int_to_hex(args[0][2:-1]).zfill(4)
                    word0_second_half = opcode_val.zfill(4)

                    hex_file_str = write_two_lines_to_hexfile(
                        word0_first_half, word0_second_half, word1,
                        hex_file_str)

                elif re.match(util.REGEX_UV_ONE, args[0]) and len(args) == 2:
                    valid_opcode = True
                    letters_arg0 = re.findall(util.REGEX_UV_ONE, args[0])
                    i = util.UVYZ_to_hex_digit[str(letters_arg0[0])]
                    j = '0'

                    # LD R[U] R[V]
                    if re.match(util.REGEX_UV_ONE, args[1]):
                        opcode_val = util.opcode_lookup_dict['LD R[U] R[V]']
                        j = util.UVYZ_to_hex_digit[args[1][2:-1]]

                    # LD R[U] R[i]
                    elif re.match(r'R\[\d+]', args[1]):
                        opcode_val = util.opcode_lookup_dict['LD R[U] R[i]']
                        word1 = util.int_to_hex(args[1][2:-1]).zfill(8)

                    # LD R[U] i
                    elif re.match(r'\d+', args[1]):
                        opcode_val = util.opcode_lookup_dict['LD R[U] i']
                        word1 = util.int_to_hex(args[1]).zfill(8)

                    word0_first_half = i + j + '00'
                    word0_second_half = opcode_val.zfill(4)

                    hex_file_str = write_two_lines_to_hexfile(
                        word0_first_half, word0_second_half, word1,
                        hex_file_str)

                elif re.match(util.REGEX_UV_TWO, args[0]):
                    valid_opcode = True
                    letters_arg0 = re.findall(util.REGEX_UV_TWO, args[0])
                    i = util.UVYZ_to_hex_digit[str(letters_arg0[0][0])]
                    j = util.UVYZ_to_hex_digit[str(letters_arg0[0][1])]
                    k = '0'
                    l = '0'

                    # LD R[U:V] R[i]
                    if re.match(r'R\[\d+]', args[1]):
                        opcode_val = util.opcode_lookup_dict['LD R[U:V] R[i]']
                        word1 = util.int_to_hex(args[1][2:-1]).zfill(8)

                    # LD R[U:V] i
                    if re.match(r'\d+', args[1]):
                        opcode_val = util.opcode_lookup_dict['LD R[U:V] i']
                        word1 = util.int_to_hex(args[1]).zfill(8)

                    # LD R[U:V] R[Y]
                    elif re.match(util.REGEX_UV_ONE, args[1]):
                        opcode_val = util.opcode_lookup_dict['LD R[U:V] R[Y]']
                        k = re.findall(util.REGEX_UV_ONE, args[1])[0]
                        k = util.UVYZ_to_hex_digit[k]

                    # LD R[U:V] R[Y:Z]
                    elif re.match(util.REGEX_UV_TWO, args[1]):
                        opcode_val = util.opcode_lookup_dict[
                            'LD R[U:V] R[Y:Z]']

                        k_and_l = re.findall(util.REGEX_UV_TWO, args[1])
                        k = util.UVYZ_to_hex_digit[str(k_and_l[0][0])]
                        l = util.UVYZ_to_hex_digit[str(k_and_l[0][1])]

                    word0_first_half = i + j + k + l
                    word0_second_half = opcode_val.zfill(4)

                    hex_file_str = write_two_lines_to_hexfile(
                        word0_first_half, word0_second_half, word1,
                        hex_file_str)

                if not valid_opcode:
                    msg = 'invalid syntax'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

            elif opcode == 'ADD':
                valid_opcode = True
                if len(args) < 2 or not re.match(util.REGEX_LD_R_ONE, args[0]):
                    msg = f'requires 2 or more arguments after {opcode}'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

                elif re.match(util.REGEX_LD_R_ONE, args[1]):
                    opcode_val = util.opcode_lookup_dict[
                        'REGISTER TO REGISTER ADD']
                    word1 = util.int_to_hex(args[1][2:-1]).zfill(8)

                else:
                    opcode_val = util.opcode_lookup_dict['DIRECT ADD']
                    word1 = util.int_to_hex(args[1]).zfill(8)

                word0_first_half = util.int_to_hex(args[0][2:-1]).zfill(4)
                word0_second_half = opcode_val.zfill(4)

            elif opcode == 'SUB':
                valid_opcode = True
                if len(args) < 2 or not re.match(util.REGEX_LD_R_ONE, args[0]):
                    msg = f'requires 2 or more arguments after {opcode}'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

                elif re.match(util.REGEX_LD_R_ONE, args[1]):
                    opcode_val = util.opcode_lookup_dict[
                        'REGISTER TO REGISTER SUBTRACT']
                    word1 = util.int_to_hex(args[1][2:-1]).zfill(8)

                else:
                    opcode_val = util.opcode_lookup_dict['DIRECT SUBTRACT']
                    word1 = util.int_to_hex(args[1]).zfill(8)

                word0_first_half = util.int_to_hex(args[0][2:-1]).zfill(4)
                word0_second_half = opcode_val.zfill(4)

            elif opcode == 'MUL':
                valid_opcode = True
                if len(args) < 2 or not re.match(util.REGEX_LD_R_ONE, args[0]):
                    msg = f'requires 2 or more arguments after {opcode}'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)
                elif re.match(util.REGEX_LD_R_ONE, args[1]):
                    opcode_val = util.opcode_lookup_dict[
                        'REGISTER TO REGISTER MULTIPLY']
                    word1 = util.int_to_hex(args[1][2:-1]).zfill(8)

                else:
                    opcode_val = util.opcode_lookup_dict['DIRECT MULTIPLY']
                    word1 = util.int_to_hex(args[1]).zfill(8)

                word0_first_half = util.int_to_hex(args[0][2:-1]).zfill(4)
                word0_second_half = opcode_val.zfill(4)

            elif opcode == 'DIV':
                valid_opcode = True

                if len(args) < 2 or not re.match(util.REGEX_LD_R_ONE, args[0]):
                    msg = f'requires 2 or more arguments after {opcode}'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

                elif re.match(util.REGEX_LD_R_ONE, args[1]):
                    opcode_val = util.opcode_lookup_dict[
                        'REGISTER TO REGISTER DIVIDE']
                    word1 = util.int_to_hex(args[1][2:-1]).zfill(8)

                else:
                    opcode_val = util.opcode_lookup_dict['DIRECT DIVIDE']
                    word1 = util.int_to_hex(args[1]).zfill(8)

                # check if dividing by 0
                if word1 == '00000000':
                    msg = f'attempting to divide by zero'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

                word0_first_half = util.int_to_hex(args[0][2:-1]).zfill(4)
                word0_second_half = opcode_val.zfill(4)

            elif opcode == 'REM':
                valid_opcode = True

                if len(args) < 2 or not re.match(util.REGEX_LD_R_ONE, args[0]):
                    msg = f'requires 2 or more arguments after {opcode}'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

                elif re.match(util.REGEX_LD_R_ONE, args[1]):
                    opcode_val = util.opcode_lookup_dict[
                        'REGISTER TO REGISTER REMAINDER']
                    word1 = util.int_to_hex(args[1][2:-1]).zfill(8)

                else:
                    opcode_val = util.opcode_lookup_dict['DIRECT REMAINDER']
                    word1 = util.int_to_hex(args[1]).zfill(8)

                # check if remainder by 0
                if word1 == '00000000':
                    msg = f'attempting to divide by zero'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

                word0_first_half = util.int_to_hex(args[0][2:-1]).zfill(4)
                word0_second_half = opcode_val.zfill(4)

            # ==
            elif opcode == 'CMP':
                valid_opcode = True
                if len(args) < 2:
                    msg = f'requires 2 or more arguments after {opcode}'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

                elif re.match(util.REGEX_LD_R_ONE, args[0]):
                    if re.match(util.REGEX_LD_R_ONE, args[1]):
                        opcode_val = util.opcode_lookup_dict[
                            'COMPARE REGISTER TO REGISTER']
                        word1 = util.int_to_hex(args[1][2:-1]).zfill(8)

                        word0_first_half = util.int_to_hex(
                            args[0][2:-1]).zfill(4)
                        word0_second_half = opcode_val.zfill(4)

                    else:
                        opcode_val = util.opcode_lookup_dict[
                            'COMPARE REGISTER TO DIRECT']
                        word1 = util.int_to_hex(args[1]).zfill(8)

                        word0_first_half = util.int_to_hex(
                            args[0][2:-1]).zfill(4)
                        word0_second_half = opcode_val.zfill(4)

                elif re.match(util.REGEX_UV_ONE, args[0]):
                    letters_arg0 = re.findall(util.REGEX_UV_ONE, args[0])
                    i = util.UVYZ_to_hex_digit[str(letters_arg0[0])]

                    if re.match(r'\d+', args[1]):
                        opcode_val = util.opcode_lookup_dict[
                            'COMPARE UV TO DIRECT']
                        word1 = util.int_to_hex(args[1]).zfill(8)

                        word0_first_half = i + '000'
                        word0_second_half = opcode_val.zfill(4)

                hex_file_str = write_two_lines_to_hexfile(
                    word0_first_half, word0_second_half, word1, hex_file_str)

            # <
            elif opcode == 'LT':
                valid_opcode = True
                if len(args) < 2 or not re.match(util.REGEX_LD_R_ONE, args[0]):
                    msg = f'requires 2 or more arguments after {opcode}'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)
                elif re.match(util.REGEX_LD_R_ONE, args[1]):
                    opcode_val = util.opcode_lookup_dict[
                        'LESS THAN REGISTER TO REGISTER']
                    word1 = util.int_to_hex(args[1][2:-1]).zfill(8)

                else:
                    opcode_val = util.opcode_lookup_dict[
                        'LESS THAN REGISTER TO DIRECT']
                    word1 = util.int_to_hex(args[1]).zfill(8)

                word0_first_half = util.int_to_hex(args[0][2:-1]).zfill(4)
                word0_second_half = opcode_val.zfill(4)

            # <=
            elif opcode == 'LTE':
                valid_opcode = True
                if len(args) < 2 or not re.match(util.REGEX_LD_R_ONE, args[0]):
                    msg = f'requires 2 or more arguments after {opcode}'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)
                elif re.match(util.REGEX_LD_R_ONE, args[1]):
                    opcode_val = util.opcode_lookup_dict[
                        'LESS THAN OR EQUAL REGISTER TO REGISTER']
                    word1 = util.int_to_hex(args[1][2:-1]).zfill(8)

                else:
                    opcode_val = util.opcode_lookup_dict[
                        'LESS THAN OR EQUAL REGISTER TO DIRECT']
                    word1 = util.int_to_hex(args[1]).zfill(8)

                word0_first_half = util.int_to_hex(args[0][2:-1]).zfill(4)
                word0_second_half = opcode_val.zfill(4)

            # >
            elif opcode == 'GT':
                valid_opcode = True
                if len(args) < 2 or not re.match(util.REGEX_LD_R_ONE, args[0]):
                    msg = f'requires 2 or more arguments after {opcode}'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)
                elif re.match(util.REGEX_LD_R_ONE, args[1]):
                    opcode_val = util.opcode_lookup_dict[
                        'STRICT GREATER THAN REGISTER TO REGISTER']
                    word1 = util.int_to_hex(args[1][2:-1]).zfill(8)

                else:
                    opcode_val = util.opcode_lookup_dict[
                        'STRICT GREATER THAN REGISTER TO DIRECT']
                    word1 = util.int_to_hex(args[1]).zfill(8)

                word0_first_half = util.int_to_hex(args[0][2:-1]).zfill(4)
                word0_second_half = opcode_val.zfill(4)

            # >=
            elif opcode == 'GTE':
                valid_opcode = True
                if len(args) < 2 or not re.match(util.REGEX_LD_R_ONE, args[0]):
                    msg = f'requires 2 or more arguments after {opcode}'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)
                elif re.match(util.REGEX_LD_R_ONE, args[1]):
                    opcode_val = util.opcode_lookup_dict[
                        'GREATER THAN OR EQUAL REGISTER TO REGISTER']
                    word1 = util.int_to_hex(args[1][2:-1]).zfill(8)

                else:
                    opcode_val = util.opcode_lookup_dict[
                        'GREATER THAN OR EQUAL REGISTER TO DIRECT']
                    word1 = util.int_to_hex(args[1]).zfill(8)

                word0_first_half = util.int_to_hex(args[0][2:-1]).zfill(4)
                word0_second_half = opcode_val.zfill(4)

            elif opcode == 'CALL':
                valid_opcode = True
                if len(args) < 1:
                    msg = f'requires 1 or more arguments after {opcode}'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

                # CALL LABEL
                elif re.match(util.REGEX_LABEL, args[0]):
                    opcode_val = util.opcode_lookup_dict['CALL']

                    if args[0] not in LABELS_TO_PC.keys():
                        raise Exception('\nUnknown Label %s' % args[0])
                    word1 = util.int_to_hex(LABELS_TO_PC[args[0]]).zfill(8)

                # CALL i
                elif re.match(util.REGEX_INT, args[0]):
                    opcode_val = util.opcode_lookup_dict['CALL']
                    word1 = util.int_to_hex(args[0]).zfill(8)

                # CALL R[i]
                elif re.match(util.REGEX_LD_R_ONE, args[0]):
                    opcode_val = util.opcode_lookup_dict['CALL R[i]']
                    word1 = util.int_to_hex(args[0][2:-1]).zfill(8)

                word0_second_half = opcode_val.zfill(4)

            elif opcode == 'RETURN':
                valid_opcode = True

                if len(args) > 0:
                    msg = f'no args after {opcode}'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

                opcode_val = util.opcode_lookup_dict['RETURN']
                word0_second_half = opcode_val.zfill(4)

            elif opcode in ('POP', 'PUSH'):
                valid_opcode = True
                if len(args) > 0:
                    msg = f'no args after {opcode}'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

                opcode_val = util.opcode_lookup_dict[opcode]
                word0_second_half = opcode_val.zfill(4)

            elif opcode == 'BLIT':
                valid_opcode = True

                if len(args) > 0:
                    msg = f'no args after {opcode}'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

                opcode_val = util.opcode_lookup_dict['BLIT']
                word0_second_half = opcode_val.zfill(4)

            elif opcode == 'RAND':
                valid_opcode = True
                opcode_val = util.opcode_lookup_dict[opcode]
                word0_second_half = opcode_val.zfill(4)

                if len(args) != 1:
                    msg = f'1 arg after {opcode}'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

                elif re.match(r'R\[\d+]', args[0]):
                    word1 = util.int_to_hex(args[0][2:-1]).zfill(8)

                else:
                    msg = 'invalid syntax'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

            elif opcode == 'INPUT':
                valid_opcode = True
                opcode_val = util.opcode_lookup_dict[opcode]
                word0_second_half = opcode_val.zfill(4)

                if len(args) == 1 and re.match(util.REGEX_LD_R_ONE, args[0]):
                    ram_slot_idx = re.findall(r'R\[(\d+)]', args[0])[0]
                    word0_first_half = util.int_to_hex(ram_slot_idx).zfill(4)

                else:
                    msg = 'invalid syntax'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

            elif opcode == 'SHT':  # shift right plus AND
                valid_opcode = True
                opcode_val = util.opcode_lookup_dict[opcode]
                word0_second_half = opcode_val.zfill(4)

                if len(args) == 3 and (re.match(util.REGEX_LD_R_ONE, args[0])
                                       and re.match(util.REGEX_LD_R_ONE,
                                                    args[1])
                                       and re.match(r'\d+', args[2])):

                    ram_idx_from = re.findall(r'R\[(\d+)]', args[0])[0]
                    ram_idx_to = re.findall(r'R\[(\d+)]', args[1])[0]
                    bitshift = args[2]

                    word0_first_half = util.int_to_hex(ram_idx_to).zfill(4)
                    word1_first_half = util.int_to_hex(ram_idx_from).zfill(4)
                    word1_second_half = util.int_to_hex(bitshift).zfill(4)
                    word1 = word1_first_half + word1_second_half

                else:
                    msg = 'invalid syntax'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

            elif opcode == 'WAIT':  # wait 17 ms
                valid_opcode = True
                opcode_val = util.opcode_lookup_dict[opcode]
                word0_second_half = opcode_val.zfill(4)

                if len(args) > 0:
                    msg = f'no args after {opcode}'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

            elif opcode == 'EXIT':
                valid_opcode = True
                opcode_val = util.opcode_lookup_dict['EXIT']
                word0_second_half = opcode_val.zfill(4)

                if len(args) > 0:
                    msg = f'no args after {opcode}'
                    num_errors = error_msg(file_asm, line_idx, line,
                                           num_errors, msg)

            # write lines for LD and CMP
            if valid_opcode and opcode not in ['LD', 'CMP']:
                hex_file_str = write_two_lines_to_hexfile(
                    word0_first_half, word0_second_half, word1, hex_file_str)

    return hex_file_str, num_errors