view python/ppci/target/arm/instructions.py @ 346:3bb7dcfe5529

expanded arm target
author Windel Bouwman
date Fri, 07 Mar 2014 17:05:32 +0100
parents b4882ff0ed06
children 2b02bd286fe9
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 Dcd(ArmInstruction):
    def __init__(self, v):
        super().__init__()
        self.v = v

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


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 relocations(self):
        return []

    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 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 Mul(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 'add {}, {}, {}'.format(self.rd, self.rn, self.rm)


class Add1(OpRegRegReg):
    opcode = 0b0000100


class Sub1(OpRegRegReg):
    opcode = 0b0000010


class Orr1(OpRegRegReg):
    opcode = 0b0001100


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 'add {}, {}, {}'.format(self.rd, self.rn, self.imm)


class Add2(OpRegRegImm):
    opcode = 0b0010100


class Sub2(OpRegRegImm):
    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')]


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 Ble(BranchBase):
    cond = LE

class Blt(BranchBase):
    cond = LT


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

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 Ldr(*args):
    if len(args) == 3 and isinstance(args[1], ArmRegister):
        return Ldr1(*args)
    elif len(args) == 2 and isinstance(args[1], ArmRegister):
        return Ldr1(args[0], args[1], 0)
    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()


class Str1(LdrStrBase):
    opcode = 0b010
    bit20 = 0


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


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