def encode_op2(op2): """ check_op2 must be called before this. Argument op2 must be a string. Encode the op2. Return a tuple of I-flag and an integer containing the other 12 bits. """ operands = [x.strip() for x in op2.split(',')] if len(operands) == 1: if helpers.is_reg(operands[0]): # op2 = reg iflag = False reg = helpers.get_reg_num(operands[0]) shifttype = 'LSL' shiftby = 0 shiftbyreg = False else: # op2 = immediate value iflag = True op2field = helpers.encode_imval(operands[0]) else: iflag = False reg = helpers.get_reg_num(operands[0]) if '#' in operands[1]: operands[1] = operands[1][:operands[1].find( '#' )] + ' ' + operands[1][operands[1].find( '#' ):] # make it legal to omit the space between shiftname and immediate value shift = [x.strip() for x in operands[1].split()] if len(shift) == 1: # RRX shifttype = 'ROR' shiftby = 0 shiftbyreg = False else: shifttype = shift[0] if helpers.is_reg(shift[1]): shiftby = helpers.get_reg_num(shift[1]) shiftbyreg = True else: shiftby = helpers.imval_to_int(shift[1]) shiftbyreg = False if shiftby == 0: shifttype = 'LSL' if shifttype.upper() in ['LSR', 'ASR'] and shiftby == 32: shiftby = 0 if not iflag: shiftfield = ({ 'LSL': 0, 'ASL': 0, 'LSR': 1, 'ASR': 2, 'ROR': 3 }[shifttype.upper()] << 1) | shiftbyreg if shiftbyreg: shiftfield = (shiftby << 4) | shiftfield else: shiftfield = (shiftby << 3) | shiftfield op2field = (shiftfield << 4) | reg return (iflag, op2field)
def get_directive_size(name, operands, address): """ Do not check the syntax or the content, just return how many bytes it will be if it is valid, and store included files using filedict. name must be the name of a directive in uppercase, operands the operands, address the address where it is. Return -1 on failure (invalid name). """ if name == 'DCD' or name == 'DCDU': padding = 0 if name == 'DCD': padding = ((4 - (address % 4)) % 4) operands = operands.split(',') return padding + 4 * len(operands) elif name == 'DCW' or name == 'DCWU': padding = 0 if name == 'DCW': padding = address % 2 operands = operands.split(',') return padding + 2 * len(operands) elif name == 'ALIGN': operands = operands.split(',') alignment = 4 offset = 0 if operands[0] != '': alignment = helpers.imval_to_int('#' + operands[0]) if len(operands) > 1: offset = helpers.imval_to_int('#' + operands[1]) return (alignment - ((address + alignment - offset) % alignment)) % alignment elif name == 'DCB': size = 0 operands = operands.split(',') for i in operands: i = i.strip() if i[0] == '"': i = i[1:-1] size += len(i) else: size += 1 return size elif name == 'INCBIN': size = filedict.add_file(operands) return size else: return -1
def encode_swiop(name, condcode, operands): """ check_swiop must be called before this. Encode the instruction and return it as a bytearray object. """ operands = operands.strip() ccval = helpers.get_condcode_value(condcode) com = helpers.imval_to_int(operands) encoded = helpers.encode_32bit([(28, 4, ccval), (24, 4, 0xF), (0, 24, com)]) return helpers.bigendian_to_littleendian(encoded)
def check_op2(op2): """ Check Op2 of a dataprocop. Return an error string if invalid, empty string otherwise. """ operands = [x.strip() for x in op2.split(',')] if len(operands) == 1: if helpers.is_reg(operands[0]): # op2 = reg return '' if not helpers.is_valid_imval(operands[0]): # op2 = immediate return 'Invalid op2 (must be of the form "reg" or "reg, shift" or "immediate value")' # constant must be expressable as "8bit unsigned int" rotated right by 2*n with n an "4 bit unsigned int" if not helpers.is_expressable_imval(operands[0]): return 'This immediate value cannot be encoded as op2' return '' if len(operands) != 2: return 'Invalid op2 (must be of the form "reg" or "reg, shift" or "immediate value")' # ->must be of form "reg, shift" if not helpers.is_reg(operands[0]): return 'Invalid op2 (must be of the form "reg" or "reg, shift" or "immediate value")' if '#' in operands[1]: operands[1] = operands[1][:operands[1].find( '#' )] + ' ' + operands[1][operands[1].find( '#' ):] # make it legal to omit the space between shiftname and immediate value shift = [x.strip() for x in operands[1].split()] if len(shift) == 1: # "RRX" or "shiftname reg" or "shiftname immediate" if shift[0] != 'RRX': return 'Invalid op2 (must be of the form "reg" or "reg, shift" or "immediate value")' return '' elif len(shift) > 2: return 'Invalid op2 (must be of the form "reg" or "reg, shift" or "immediate value")' if not helpers.is_shiftname(shift[0]): return 'Invalid op2 (must be of the form "reg" or "reg, shift" or "immediate value")' if helpers.is_reg(shift[1]): if helpers.get_reg_num(shift[1]) == 15: return 'PC may not be used here' return '' if not helpers.is_valid_imval(shift[1]): return 'Invalid op2 (must be of the form "reg" or "reg, shift" or "immediate value")' amount = helpers.imval_to_int(shift[1]) if amount >= 0 and amount <= 31: return '' elif amount == 32 and shift[0] not in ['LSR', 'ASR']: return 'Shift by 32 is only allowed for LSR' return 'Invalid immediate shift amount. Must be 0 <= amount <= 31 (or 32 for special LSR, ASR)'
def check_swiop(name, operands): """ Assumes valid name, valid name+flags combination, valid condcode. Check the operands and return an error string if invalid, empty string otherwise. """ operands = [x.strip() for x in operands.split(',')] if len(operands) != 1: return 'Invalid number of operands: expected 1, got %i' % (len(operands)) operands = operands[0] if not helpers.is_valid_imval(operands): return 'Invalid operand: expected immediate value' com = helpers.imval_to_int(operands) if com > 2**24-1: return 'Operand greater than 2^24-1' if com < -2**23: return 'Operand lower than -2^23' return ''
def is_valid_addresspart(hsflag, addresspart, tflag, address, labeldict): """ hsflag = True -> selects syntax checking for halfword or signed data transfer instructions, False selects normal unsigned word/byte transfer syntax. Address must be the address of this instruction. Return empty string if addresspart is valid according to the syntax rules for datatransfer address part, error string otherwise. """ if len(addresspart) < 1: return 'Address part is missing' if addresspart[ 0] != '[': # must be an expression (label) if not starting with a bracket if addresspart not in labeldict: return 'Expected bracket or label' offset = labeldict[addresspart] - address - 8 addresspart = '[PC, #' + str(offset) + ']' # range check done below writeback = False if addresspart[-1] == '!': writeback = True addresspart = addresspart[:-1].strip() # strip the trailing ! if addresspart[-1] == ']': preindexed = True addresspart = addresspart[:-1].strip() # strip the trailing ] else: if writeback: return '! is only allowed for preindexed addressing' preindexed = False addresspart = addresspart[1:].strip() # strip the leading [ addresspart = [x.strip() for x in addresspart.split(',')] if len(addresspart) < 1 or len(addresspart) > 3 or (hsflag and len(addresspart) > 2): return 'Invalid addresspart' if not preindexed: if addresspart[0][-1:] != ']': return 'Expected closing ]' addresspart[0] = addresspart[0][:-1].strip() # strip the trailing ] # there should be no syntax differences between pre- and post-indexing left if not helpers.is_reg(addresspart[0]): return 'Expected register as base' if writeback and helpers.get_reg_num(addresspart[0]) == 15: return 'Write-back should not be used when PC is the base register' if preindexed and tflag: return 'T-flag is not allowed when pre-indexing is used' if len(addresspart) == 1: return '' if helpers.is_valid_imval(addresspart[1]): n = helpers.imval_to_int(addresspart[1]) if hsflag: limit = 2**8 - 1 else: limit = 2**12 - 1 if n > limit: return 'Offset too high (max. %i)' % (limit) if n < -limit: return 'Offset too low (min. %i)' % (-limit) if len(addresspart) > 2: return 'Too many operands' return '' else: if len(addresspart[1]) < 2: return 'Invalid offset' if addresspart[1][0] in ['+', '-']: addresspart[1] = addresspart[1][1:] if not helpers.is_reg(addresspart[1]): return 'Invalid offset: must be register or immediate value' if helpers.get_reg_num(addresspart[1]) == 15: return 'PC is not allowed as offset' if not preindexed and helpers.get_reg_num( addresspart[0]) == helpers.get_reg_num(addresspart[1]): return 'Manual says: post-indexed with Rm = Rn should not be used' if len(addresspart) == 2: return '' if hsflag: return 'Expected less operands' # addresspart[2] should be a shift: if len(addresspart[2]) < 3: return 'Invalid shift expression' shift = addresspart[2] if shift.upper() == 'RRX': return '' shift = shift.split() if len(shift) == 1 and '#' in shift[0]: shift = shift[0].split('#') shift[1] = '#' + shift[1] if len(shift) != 2: return 'Invalid shift expression' if not helpers.is_shiftname(shift[0]): return 'Invalid shift name' if helpers.is_reg(shift[1]): return 'Register specified shift amount is not allowed in data transfer instructions' if not helpers.is_valid_imval(shift[1]): return 'Invalid shift amount' n = helpers.imval_to_int(shift[1]) if n >= 0 and n <= 31: return '' elif n == 32 and shift[0] not in ['LSR', 'ASR']: return 'Shift by 32 is only allowed for LSR' return 'Invalid immediate shift amount. Must be 0 <= amount <= 31 (or 32 for special LSR, ASR)'
def parse_datatrans(name, operands, address, labeldict): """ check_singledatatransop or check_halfsigneddatatransop must be called before this. Does the stuff common to halfsigned and normal datatrans encoding. """ if operands.count('[') == 0: label = operands.split(',')[1].strip() offset = labeldict[label] - address - 8 operands = operands.split(',')[0] + ',[PC, #' + str(offset) + ']' writeback = (operands[-1] == '!') if writeback: operands = operands[:-1].strip() preindexed = (operands[-1] == ']') if preindexed: operands = operands[:-1].strip() loadflag = (name == 'LDR') operands = [x.strip() for x in operands.split(',')] operands[1] = operands[1][1:].strip() if operands[1][-1] == ']': operands[1] = operands[1][:-1].strip() rd = helpers.get_reg_num(operands[0]) rn = helpers.get_reg_num(operands[1]) offset = 0 upflag = True iflag = False if len(operands) > 2: if helpers.is_valid_imval(operands[2]): iflag = False # !!! offset = helpers.imval_to_int(operands[2]) upflag = (offset >= 0) offset = abs(offset) else: iflag = True upflag = True if operands[2][0] == '-': upflag = False operands[2] = operands[2][1:] elif operands[2][0] == '+': operands[2] = operands[2][1:] rm = helpers.get_reg_num(operands[2]) shiftfield = 0 if len(operands) == 4: shift = [x.strip() for x in operands[3].split()] if len(shift) == 1: # RRX shifttype = 'ROR' shiftby = 0 else: shifttype = shift[0] shiftby = helpers.imval_to_int(shift[1]) if shiftby == 0: shifttype = 'LSL' if shifttype.upper() in ['LSR', 'ASR'] and shiftby == 32: shiftby = 0 shiftfield = (shiftby << 3) | { 'LSL': 0, 'ASL': 0, 'LSR': 1, 'ASR': 2, 'ROR': 3 }[shifttype.upper()] << 1 offset = (shiftfield << 4) | rm return (writeback, preindexed, loadflag, upflag, iflag, rd, rn, offset)