Beispiel #1
0
def check_blockdatatransop(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(',', 1)]
    if len(operands) < 2:
        return 'Too few operands'
    if len(operands[0]) < 2:
        return 'Invalid operand'
    if operands[0][-1] == '!':
        writeback = True
        operands[0] = operands[0][:-1].strip()
    else:
        writeback = False
    if not helpers.is_reg(operands[0]):
        return 'Expected register'
    base = helpers.get_reg_num(operands[0])
    if base == 15:
        return 'PC is not allowed here'
    if len(operands[1]) < 2:
        return 'Invalid operand'
    if operands[1][-1] == '^':
        sbit = True
        operands[1] = operands[1][:-1].strip()
    else:
        sbit = False
    if operands[1][0] != '{' or operands[1][-1] != '}':
        return 'Missing {} around register list'
    operands[1] = operands[1][1:-1].strip()
    operands[1] = [x.strip() for x in operands[1].split(',')]
    if len(operands[1]) < 1:
        return 'Invalid register list'
    reglist = []
    for op in operands[1]:
        if '-' in op:
            r = [x.strip() for x in op.split('-')]
            if len(r) > 2:
                return 'Invalid syntax'
            if not helpers.is_reg(r[0]) or not helpers.is_reg(r[1]):
                return 'Expected register'
            start = helpers.get_reg_num(r[0])
            end = helpers.get_reg_num(r[1])
            if start >= end:
                return 'Registers must be specified in ascending order'
            reglist += list(range(start,
                                  end + 1))  # upy needs explicit conversion
        else:
            if not helpers.is_reg(op):
                return 'Expected register'
            reglist.append(helpers.get_reg_num(op))
    for i in range(0, len(reglist) - 1):
        if reglist[i] >= reglist[i + 1]:
            return 'Registers must be specified in ascending order'
    if sbit and writeback and (name == 'STM' or
                               (name == 'LDM' and 15 not in reglist)):
        return 'Writeback may not be used combined with user bank transfer'
    if writeback and name == 'LDM' and base in reglist:
        return 'Attention: Writeback is useless here because the loaded value will overwrite it'
    return ''
Beispiel #2
0
def check_psrtransop(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) != 2:
        return 'Invalid number of operands: expected 2, got %i' % (len(operands))
    if name == 'MRS':
        if not helpers.is_reg(operands[0]):
            return 'Invalid operand: expected register'
        rd = helpers.get_reg_num(operands[0])
        if rd == 15:
            return 'PC is not allowed here'
        if not operands[1].upper() in ['SPSR', 'SPSR_ALL', 'CPSR', 'CPSR_ALL']:
            return 'Invalid operand: expected psr'
        return ''
    else:
        if not helpers.is_psr(operands[0]):
            return 'Invalid operand: expected psr'
        if not operands[0].upper().endswith('FLG'):
            if not helpers.is_reg(operands[1]):  # immediate is only allowed for PSR_FLG
                return 'Invalid operand: expected register'
            if helpers.get_reg_num(operands[1]) == 15:
                return 'PC is not allowed here'
            return ''
        if helpers.is_reg(operands[1]):
            if helpers.get_reg_num(operands[1]) == 15:
                return 'PC is not allowed here'
            return ''
        if not helpers.is_valid_imval(operands[1]):
            return 'Invalid operand: expected register or immediate value'
        if not helpers.is_expressable_imval(operands[1]):
            return 'This immediate value cannot be encoded'
        return ''
Beispiel #3
0
def encode_dataprocop(name, flags, condcode, operands):
    """
    check_dataprocop must be called before this.
    Encode the instruction and return it as a bytearray object.
    """
    operands = [x.strip() for x in operands.split(',')]
    sflag = (flags == 'S')
    if helpers.is_dataproc_fullop(name):
        dest = helpers.get_reg_num(operands[0])
        op1 = helpers.get_reg_num(operands[1])
        (iflag, op2) = encode_op2(','.join(operands[2:]))
    elif helpers.is_dataproc_testop(name):
        dest = 0
        op1 = helpers.get_reg_num(operands[0])
        (iflag, op2) = encode_op2(','.join(operands[1:]))
        sflag = True
    else:  # movop
        dest = helpers.get_reg_num(operands[0])
        op1 = 0
        (iflag, op2) = encode_op2(','.join(operands[1:]))
    ccval = helpers.get_condcode_value(condcode)
    dpn = helpers.get_dataprocop_num(name)
    encoded = helpers.encode_32bit([(28, 4, ccval), (25, 1, iflag),
                                    (21, 4, dpn), (20, 1, sflag), (16, 4, op1),
                                    (12, 4, dest), (0, 12, op2)])
    return helpers.bigendian_to_littleendian(encoded)
Beispiel #4
0
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)
Beispiel #5
0
def encode_miscarithmeticop(name, condcode, operands):
    """
    check_miscarithmeticop must be called before this.
    Encode the instruction and return it as a bytearray object.
    """
    operands = [x.strip() for x in operands.split(',')]
    rd = helpers.get_reg_num(operands[0])
    rm = helpers.get_reg_num(operands[1])
    ccval = helpers.get_condcode_value(condcode)
    encoded = helpers.encode_32bit([(28, 4, ccval), (16, 12, 0x16F), (12, 4, rd), (4, 8, 0xF1), (0, 4, rm)])
    return helpers.bigendian_to_littleendian(encoded)
Beispiel #6
0
def encode_blockdatatransop(name, flags, condcode, operands):
    """
    check_blockdatatransop must be called before this.
    Encode the instruction and return it as a bytearray object.
    """
    operands = [x.strip() for x in operands.split(',')]
    if operands[0][-1] == '!':
        writeback = True
        operands[0] = operands[0][:-1].strip()
    else:
        writeback = False
    base = helpers.get_reg_num(operands[0])
    if operands[-1][-1] == '^':
        sbit = True
        operands[-1] = operands[-1][:-1].strip()
    else:
        sbit = False
    operands[1] = operands[1][1:].strip()  # strip the curly brackets
    operands[-1] = operands[-1][:-1].strip()
    reglist = []
    for op in operands[1:]:
        if '-' in op:
            (start,
             end) = [helpers.get_reg_num(r.strip()) for r in op.split('-')]
            reglist += list(range(start,
                                  end + 1))  # upy needs explicit conversion
        else:
            reglist.append(helpers.get_reg_num(op))
    regfield = 0
    for r in reglist:
        regfield |= (1 << r)
    lflag = (name == 'LDM')
    addrmodedict = {
        'ED': (lflag, lflag),
        'IB': (1, 1),
        'FD': (lflag, not lflag),
        'IA': (1, 0),
        'EA': (not lflag, lflag),
        'DB': (0, 1),
        'FA': (not lflag, not lflag),
        'DA': (0, 0)
    }
    (uflag, pflag) = addrmodedict[flags]
    ccval = helpers.get_condcode_value(condcode)
    encoded = helpers.encode_32bit([(28, 4, ccval), (25, 3, 0x4),
                                    (24, 1, pflag), (23, 1, uflag),
                                    (22, 1, sbit), (21, 1, writeback),
                                    (20, 1, lflag), (16, 4, base),
                                    (0, 16, regfield)])
    return helpers.bigendian_to_littleendian(encoded)
Beispiel #7
0
def check_branchop(name, operands, address, labeldict):
    """
    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 name == 'BX':
        operands = operands.strip()
        if not helpers.is_reg(operands):
            return 'Invalid Operand: Expected register'
        rn = helpers.get_reg_num(operands)
        if rn == 15:
            return 'PC not allowed here (causes undefined behaviour)'
        return ''
    else:
        operands = operands.strip()
        err = helpers.check_pcrelative_expression(operands, labeldict)
        if len(err) != 0:
            return 'Invalid Operand: Expected pc relative expression (%s)' % (err)
        offset = helpers.pcrelative_expression_to_int(operands, address, labeldict)
        if offset % 4 != 0:
            return 'Offset must be aligned to four bytes'
        offset >>= 2
        if offset < -2**23 or offset > 2**23-1:
            return 'Branch target too far away'
        return ''
Beispiel #8
0
def check_miscarithmeticop(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) != 2:
        return 'Invalid number of operands: expected 2, got %i' % (len(operands))
    if not helpers.is_reg(operands[0]):
        return 'Invalid operand: expected register'
    rd = helpers.get_reg_num(operands[0])
    if not helpers.is_reg(operands[1]):
        return 'Invalid operand: expected register'
    rm = helpers.get_reg_num(operands[1])
    if rd == 15 or rm == 15:
        return 'PC is not allowed here'
    return ''
Beispiel #9
0
def encode_longmulop(name, flags, condcode, operands):
    """
    check_longmulop must be called before this.
    Encode the instruction and return it as a bytearray object.
    """
    (rdlo, rdhi, rm, rs) = [helpers.get_reg_num(x.strip()) for x in operands.split(',')]
    sflag = (flags == 'S')
    signedflag = (name[0] == 'S')
    aflag = (name[3] == 'A')
    ccval = helpers.get_condcode_value(condcode)
    encoded = helpers.encode_32bit([(28, 4, ccval), (23, 5, 0x1), (22, 1, signedflag), (21, 1, aflag),
                                    (20, 1, sflag), (16, 4, rdhi), (12, 4, rdlo), (8, 4, rs), (4, 4, 0x9), (0, 4, rm)])
    return helpers.bigendian_to_littleendian(encoded)
Beispiel #10
0
def encode_swapop(name, flags, condcode, operands):
    """
    check_swapop must be called before this.
    Encode the instruction and return it as a bytearray object.
    """
    operands = [x.strip() for x in operands.split(',')]
    operands[2] = operands[2][1:-1].strip()
    operands = [helpers.get_reg_num(x) for x in operands]
    byteflag = (flags == 'B')
    ccval = helpers.get_condcode_value(condcode)
    encoded = helpers.encode_32bit([(28, 4, ccval), (23, 5, 0x2),
                                    (22, 1, byteflag), (16, 4, operands[2]),
                                    (12, 4, operands[0]), (4, 4, 0x9),
                                    (0, 4, operands[1])])
    return helpers.bigendian_to_littleendian(encoded)
Beispiel #11
0
def encode_psrtransop(name, condcode, operands):
    """
    check_psrtransop must be called before this.
    Encode the instruction and return it as a bytearray object.
    """
    operands = [x.strip() for x in operands.split(',')]
    if name == 'MRS':
        rd = helpers.get_reg_num(operands[0])
        if operands[1].upper()[0] == 'C':  # CPSR
            spsrflag = False
        else:
            spsrflag = True
        ccval = helpers.get_condcode_value(condcode)
        encoded = helpers.encode_32bit([(28, 4, ccval), (23, 5, 0x2), (22, 1, spsrflag), (16, 6, 0xF), (12, 4, rd)])
        return helpers.bigendian_to_littleendian(encoded)
    else:
        if operands[0].upper()[0] == 'C':  # CPSR
            spsrflag = False
        else:
            spsrflag = True
        if operands[0].upper().endswith('FLG'):
            allflag = False
        else:
            allflag = True
        if helpers.is_reg(operands[1]):
            iflag = False
            rm = helpers.get_reg_num(operands[1])
            op2field = rm
        else:
            iflag = True
            op2field = helpers.encode_imval(operands[1])
        ccval = helpers.get_condcode_value(condcode)
        encoded = helpers.encode_32bit([(28, 4, ccval), (25, 1, iflag), (23, 2, 0x2),
                                        (22, 1, spsrflag), (17, 5, 0x14), (16, 1, allflag),
                                        (12, 4, 0xF), (0, 12, op2field)])
        return helpers.bigendian_to_littleendian(encoded)
Beispiel #12
0
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)'
Beispiel #13
0
def check_longmulop(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) != 4:
        return 'Expected 4 operands, got %i' % len(operands)
    for o in operands:
        if not helpers.is_reg(o):
            return 'Expected a register'
    operands = [helpers.get_reg_num(x) for x in operands]
    if 15 in operands:
        return 'PC is not allowed here'
    if operands[0] == operands[1] or operands[0] == operands[2] or operands[1] == operands[2]:
        return 'RdHi, RdLo and Rm must all be different registers'
    return ''
Beispiel #14
0
def encode_mulop(name, flags, condcode, operands):
    """
    check_mulop must be called before this.
    Encode the instruction and return it as a bytearray object.
    """
    operands = [helpers.get_reg_num(x.strip()) for x in operands.split(',')]
    sflag = (flags == 'S')
    (rd, rm, rs) = operands[0:3]
    if name == 'MUL':
        rn = 0
        aflag = False
    else:
        rn = operands[3]
        aflag = True
    ccval = helpers.get_condcode_value(condcode)
    encoded = helpers.encode_32bit([(28, 4, ccval), (21, 1, aflag), (20, 1, sflag), (16, 4, rd),
                                    (12, 4, rn), (8, 4, rs), (4, 4, 0x9), (0, 4, rm)])
    return helpers.bigendian_to_littleendian(encoded)
Beispiel #15
0
def check_mulop(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 name == 'MUL' and len(operands) != 3:
        return 'Expected 3 operands, got %i' % len(operands)
    if name == 'MLA' and len(operands) != 4:
        return 'Expected 4 operands, got %i' % len(operands)
    for o in operands:
        if not helpers.is_reg(o):
            return 'Expected a register'
    operands = [helpers.get_reg_num(x) for x in operands]
    if 15 in operands:
        return 'PC is not allowed here'
    if operands[0] == operands[1]:
        return 'Rd must be different from Rm'
    return ''
Beispiel #16
0
def encode_branchop(name, condcode, operands, address, labeldict):
    """
    check_branchop must be called before this.
    Encode the instruction and return it as a bytearray object.
    """
    operands = operands.strip()
    if name == 'BX':
        rn = helpers.get_reg_num(operands)
        ccval = helpers.get_condcode_value(condcode)
        encoded = helpers.encode_32bit([(28, 4, ccval), (4, 24, 0x12FFF1), (0, 4, rn)])
        return helpers.bigendian_to_littleendian(encoded)
    else:
        offset = helpers.pcrelative_expression_to_int(operands, address, labeldict)
        offset >>= 2
        offset = offset + (offset < 0)*(1 << 24)  # correction for negative offsets
        ccval = helpers.get_condcode_value(condcode)
        lflag = (name == 'BL')
        encoded = helpers.encode_32bit([(28, 4, ccval), (25, 3, 0x5), (24, 1, lflag), (0, 24, offset)])
        return helpers.bigendian_to_littleendian(encoded)
Beispiel #17
0
def check_swapop(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) != 3:
        return 'Expected 3 operands, got %i' % (len(operands))
    if len(operands[2]) < 4:
        return 'Invalid syntax'
    if operands[2][0] != '[' or operands[2][-1] != ']':
        return 'Missing brackets around third operand of swap instruction'
    operands[2] = operands[2][1:-1].strip()
    for op in operands:
        if not helpers.is_reg(op):
            return 'Only registers are allowed here'
    for op in operands:
        if helpers.get_reg_num(op) == 15:
            return 'PC is not allowed here'
    return ''
Beispiel #18
0
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)
Beispiel #19
0
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)'