view python/ppci/target/arm/instructions.py @ 360:42343d189e14

Bugfix in for loop
author Windel Bouwman
date Fri, 14 Mar 2014 16:11:32 +0100
parents 52492b304adf
children c05ab629976a
line wrap: on
line source


from ..basetarget import Instruction
from ...bitfun import rotate_left

from .token import ArmToken
from .registers import R0, SP, ArmRegister


def encode_imm32(v):
    """ Bundle 32 bit value into 4 bits rotation and 8 bits value
     """
    for i in range(0, 16):
        v2 = rotate_left(v, i*2)
        if (v2 & 0xFFFFFF00) == 0:
            rotation = i
            val = v2 & 0xFF
            x = (rotation << 8) | val
            return x
    raise Exception("Invalid value {}".format(v))

# Instructions:

class ArmInstruction(Instruction):
    def __init__(self):
        self.token = ArmToken()


class ConstantData(ArmInstruction):
    def __init__(self, v):
        super().__init__()
        assert isinstance(v, int)
        self.v = v

    def __repr__(self):
        return 'DCD {}'.format(hex(self.v))


class Dcd(ConstantData):
    def encode(self):
        self.token[0:32] = self.v
        return self.token.encode()

    def __repr__(self):
        return 'DCD {}'.format(hex(self.v))


class Db(ConstantData):
    def encode(self):
        assert self.v < 256
        return bytes([self.v])

    def __repr__(self):
        return 'DB {}'.format(hex(self.v))


def Mov(*args):
    if len(args) == 2:
        if isinstance(args[1], int):
            return Mov1(*args)
        elif isinstance(args[1], ArmRegister):
            return Mov2(*args)
    raise Exception()


class Mov1(ArmInstruction):
    """ Mov Rd, imm16 """
    def __init__(self, reg, imm):
        super().__init__()
        assert type(imm) is int
        self.reg = reg
        self.imm = imm

    def encode(self):
        self.token[0:12] = encode_imm32(self.imm)
        self.token.Rd = self.reg.num
        self.token[16:20] = 0
        self.token[20] = 0  # Set flags
        self.token[21:28] = 0b0011101
        self.token.cond = AL
        return self.token.encode()

    def __repr__(self):
        return 'Mov {}, {}'.format(self.reg, self.imm)


class Mov2(ArmInstruction):
    def __init__(self, rd, rm):
        super().__init__()
        self.rd = rd
        self.rm = rm

    def encode(self):
        self.token[0:4] = self.rm.num
        self.token[4:12] = 0
        self.token[12:16] = self.rd.num
        self.token[16:20] = 0
        self.token.S = 0
        self.token[21:28] = 0xD
        self.token.cond = AL
        return self.token.encode()

    def __repr__(self):
        return 'MOV {}, {}'.format(self.rd, self.rm)


def Cmp(*args):
    if len(args) == 2:
        if isinstance(args[1], int):
            return Cmp1(*args)
        elif isinstance(args[1], ArmRegister):
            return Cmp2(*args)
    raise Exception()


class Cmp1(ArmInstruction):
    """ CMP Rn, imm """
    def __init__(self, reg, imm):
        super().__init__()
        assert type(imm) is int
        self.reg = reg
        self.imm = imm

    def encode(self):
        self.token[0:12] = encode_imm32(self.imm)
        self.token.Rn = self.reg.num
        self.token[20:28] = 0b00110101
        self.token.cond = AL
        return self.token.encode()

    def __repr__(self):
        return 'CMP {}, {}'.format(self.reg, self.imm)


class Cmp2(ArmInstruction):
    """ CMP Rn, Rm """
    def __init__(self, rn, rm):
        super().__init__()
        self.rn = rn
        self.rm = rm

    def encode(self):
        self.token.Rn = self.rn.num
        self.token.Rm = self.rm.num
        self.token[7:16] = 0
        self.token[20:28] = 0b10101
        self.token.cond = AL
        return self.token.encode()

    def __repr__(self):
        return 'CMP {}, {}'.format(self.rn, self.rm)


def Add(*args):
    if len(args) == 3 and isinstance(args[0], ArmRegister) and \
            isinstance(args[1], ArmRegister):
        if isinstance(args[2], ArmRegister):
            return Add1(args[0], args[1], args[2])
        elif isinstance(args[2], int):
            return Add2(args[0], args[1], args[2])
    raise Exception()

def Sub(*args):
    if len(args) == 3 and isinstance(args[0], ArmRegister) and \
            isinstance(args[1], ArmRegister):
        if isinstance(args[2], ArmRegister):
            return Sub1(args[0], args[1], args[2])
        elif isinstance(args[2], int):
            return Sub2(args[0], args[1], args[2])
    raise Exception()


def Mul(*args):
    return Mul1(args[0], args[1], args[2])


class Mul1(ArmInstruction):
    def __init__(self, rd, rn, rm):
        super().__init__()
        self.rd = rd
        self.rn = rn
        self.rm = rm

    def encode(self):
        self.token[0:4] = self.rn.num
        self.token[4:8] = 0b1001
        self.token[8:12] = self.rm.num
        self.token[16:20] = self.rd.num
        self.token.S = 0
        self.token.cond = AL
        return self.token.encode()


class OpRegRegReg(ArmInstruction):
    """ add rd, rn, rm """
    def __init__(self, rd, rn, rm, shift=0):
        super().__init__()
        self.rd = rd
        self.rn = rn
        self.rm = rm

    def encode(self):
        self.token[0:4] = self.rm.num
        self.token[4] = 0
        self.token[5:7] = 0
        self.token[7:12] = 0 # Shift
        self.token.Rd = self.rd.num
        self.token.Rn = self.rn.num
        self.token.S = 0 # Set flags
        self.token[21:28] = self.opcode
        self.token.cond = 0xE # Always!
        return self.token.encode()

    def __repr__(self):
        return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.rm)


class Add1(OpRegRegReg):
    mnemonic = 'ADD'
    opcode = 0b0000100


class Sub1(OpRegRegReg):
    mnemonic = 'SUB'
    opcode = 0b0000010


class Orr1(OpRegRegReg):
    mnemonic = 'ORR'
    opcode = 0b0001100


class And1(OpRegRegReg):
    mnemonic = 'AND'
    opcode = 0b0000000


class ShiftBase(ArmInstruction):
    """ ? rd, rn, rm """
    def __init__(self, rd, rn, rm):
        super().__init__()
        self.rd = rd
        self.rn = rn
        self.rm = rm

    def encode(self):
        self.token[0:4] = self.rn.num
        self.token[4:8] = self.opcode
        self.token[8:12] = self.rm.num
        self.token[12:16] = self.rd.num
        self.token.S = 0 # Set flags
        self.token[21:28] = 0b1101
        self.token.cond = 0xE # Always!
        return self.token.encode()

    def __repr__(self):
        return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.rm)


class Lsr1(ShiftBase):
    mnemonic = 'LSR'
    opcode = 0b0011


class Lsl1(ShiftBase):
    mnemonic = 'LSL'
    opcode = 0b0001


class OpRegRegImm(ArmInstruction):
    """ add rd, rn, imm12 """
    def __init__(self, rd, rn, imm):
        super().__init__()
        self.rd = rd
        self.rn = rn
        self.imm2 = encode_imm32(imm)
        self.imm = imm

    def encode(self):
        self.token[0:12] = self.imm2
        self.token.Rd = self.rd.num
        self.token.Rn = self.rn.num
        self.token.S = 0 # Set flags
        self.token[21:28] = self.opcode
        self.token.cond = 0xE # Always!
        return self.token.encode()

    def __repr__(self):
        return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.imm)


class Add2(OpRegRegImm):
    mnemonic = 'ADD'
    opcode = 0b0010100


class Sub2(OpRegRegImm):
    mnemonic = 'SUB'
    opcode = 0b0010010



# Branches:

class BranchBaseRoot(ArmInstruction):
    def __init__(self, target):
        super().__init__()
        self.target = target

    def encode(self):
        self.token.cond = self.cond
        self.token[24:28] = self.opcode
        return self.token.encode()

    def relocations(self):
        return [(self.target, 'b_imm24')]

    def __repr__(self):
        mnemonic = self.__class__.__name__
        return '{} {}'.format(mnemonic, self.target)


EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL = range(15)

class BranchBase(BranchBaseRoot):
    opcode = 0b1010

class BranchLinkBase(BranchBaseRoot):
    opcode = 0b1011

class Bl(BranchLinkBase):
    cond = AL

class B(BranchBase):
    cond = AL

class Beq(BranchBase):
    cond = EQ

class Bgt(BranchBase):
    cond = GT

class Bge(BranchBase):
    cond = GE

class Ble(BranchBase):
    cond = LE

class Blt(BranchBase):
    cond = LT

class Bne(BranchBase):
    cond = NE

# Memory:

def reg_list_to_mask(reg_list):
    mask = 0
    for reg in reg_list:
        mask |= (1 << reg.num)
    return mask


class Push(ArmInstruction):
    def __init__(self, register_set):
        super().__init__()
        self.reg_list = register_set

    def encode(self):
        self.token.cond = AL
        self.token[16:28] = 0b100100101101
        reg_list = 0
        self.token[0:16] = reg_list_to_mask(self.reg_list)
        return self.token.encode()

    def __repr__(self):
        return 'PUSH {}'.format(self.reg_list)


class Pop(ArmInstruction):
    def __init__(self, register_set):
        super().__init__()
        self.reg_list = register_set

    def encode(self):
        self.token.cond = AL
        self.token[16:28] = 0b100010111101
        self.token[0:16] = reg_list_to_mask(self.reg_list)
        return self.token.encode()

    def __repr__(self):
        return 'POP {}'.format(self.reg_list)


def Ldr(*args):
    """ Convenience function that creates the correct instruction """
    if len(args) == 3:
        if isinstance(args[1], ArmRegister):
            return Ldr1(*args)
    elif len(args) == 2:
        if isinstance(args[1], ArmRegister):
            return Ldr1(args[0], args[1], 0)
        elif isinstance(args[1], str):
            return Ldr3(*args)
    raise Exception()


def Str(*args):
    if len(args) == 3 and isinstance(args[1], ArmRegister):
        return Str1(*args)
    elif len(args) == 2 and isinstance(args[1], ArmRegister):
        return Str1(args[0], args[1], 0)
    raise Exception()


class LdrStrBase(ArmInstruction):
    def __init__(self, rt, rn, offset):
        super().__init__()
        self.rt = rt
        self.rn = rn
        self.offset = offset

    def encode(self):
        self.token.cond = AL
        self.token.Rn = self.rn.num
        self.token[25:28] = self.opcode
        self.token[20] = self.bit20
        self.token[12:16] = self.rt.num
        self.token[24] = 1  # Index
        if self.offset >= 0:
            self.token[23] = 1  # U == 1 'add'
            self.token[0:12] = self.offset
        else:
            self.token[23] = 0
            self.token[0:12] = -self.offset
        return self.token.encode()

    def __repr__(self):
        return '{} {}, [{}, {}]'.format(self.mnemonic, self.rt, self.rn, 
                hex(self.offset))


class Str1(LdrStrBase):
    opcode = 0b010
    bit20 = 0
    mnemonic = 'STR'


class Ldr1(LdrStrBase):
    opcode = 0b010
    bit20 = 1
    mnemonic = 'LDR'


class Adr(ArmInstruction):
    def __init__(self, rd, label):
        super().__init__()
        self.rd = rd
        self.label = label

    def __repr__(self):
        return 'ADR {}, {}'.format(self.rd, self.label)

    def relocations(self):
        return [(self.label, 'adr_imm12')]

    def encode(self):
        self.token.cond = AL
        self.token[0:12] = 0  # Filled by linker
        self.token[12:16] = self.rd.num
        self.token[16:20] = 0b1111
        self.token[25] = 1
        return self.token.encode()


class Ldr3(ArmInstruction):
    """ Load PC relative constant value
        LDR rt, label
        encoding A1
    """
    def __init__(self, rt, label):
        super().__init__()
        self.rt = rt
        self.label = label

    def __repr__(self):
        return 'LDR {}, {}'.format(self.rt, self.label)

    def relocations(self):
        return [(self.label, 'ldr_imm12')]

    def encode(self):
        self.token.cond = AL
        self.token[0:12] = 0  # Filled by linker
        self.token[12:16] = self.rt.num
        self.token[16:23] = 0b0011111
        self.token[24:28] = 0b0101
        return self.token.encode()