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)
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