view python/cortexm3.py @ 276:56d37ed4b4d2

phaa
author Windel Bouwman
date Mon, 16 Sep 2013 21:51:17 +0200
parents 6f2423df0675
children 046017431c6a
line wrap: on
line source

import struct
import types
from target import Register, Instruction, Target, Imm8, Label, Imm3, LabelRef, Imm32, Imm7
from asmnodes import ASymbol, ANumber, AUnop, ABinop
from ppci import CompilerError
import ir

# TODO: encode this in DSL (domain specific language)
# TBD: is this required?

def u16(h):
    return struct.pack('<H', h)

def u32(x):
    return struct.pack('<I', x)

armtarget = Target('arm')

class ArmReg(Register):
    def __init__(self, num, name):
        super().__init__(name)
        self.num = num
    def __repr__(self):
        return self.name

class RegOp:
    def __init__(self, num):
        assert num < 16
        self.num = num

    @classmethod
    def Create(cls, vop):
        if type(vop) is ASymbol:
            name = vop.name
            regs = {}
            for r in armtarget.registers:
                regs[r.name] = r
            if name in regs:
                r = regs[name]
                return cls(r.num)

class Reg8Op:
    def __init__(self, num):
        assert num < 8
        self.num = num

    @classmethod
    def Create(cls, vop):
        if type(vop) is ASymbol:
            name = vop.name
            regs = {}
            for r in armtarget.registers:
                regs[r.name] = r
            if name in regs:
                r = regs[name]
                if r.num < 8:
                    return cls(r.num)

class Reg16Op:
    def __init__(self, num):
        assert num < 16
        self.num = num

    @classmethod
    def Create(cls, vop):
        if type(vop) is ASymbol:
            name = vop.name
            regs = {}
            for r in armtarget.registers:
                regs[r.name] = r
            if name in regs:
                r = regs[name]
                if r.num < 16:
                    return cls(r.num)

class RegSpOp:
    @classmethod
    def Create(cls, vop):
        if type(vop) is ASymbol:
            if vop.name.lower() == 'sp':
                return cls()

def getRegNum(n):
    for r in armtarget.registers:
        if r.num == n:
            return r

def getRegisterRange(n1, n2):
    regs = []
    if n1.num < n2.num:
        for n in range(n1.num, n2.num + 1):
            r = getRegNum(n)
            assert r
            regs.append(r)
    return regs

def isRegOffset(regname, x, y):
    if type(x) is ASymbol and type(y) is ANumber and x.name.upper() == regname:
        return y.number
    elif type(y) is ASymbol and type(x) is ANumber and y.name.upper() == regname:
        return x.number
    

class MemRegXRel:
    def __init__(self, offset):
        assert offset % 4 == 0
        self.offset = offset

    def __repr__(self):
        return '[{}, #{}]'.format(self.regname, self.offset)

    @classmethod
    def Create(cls, vop):
        if type(vop) is AUnop and vop.operation == '[]' and type(vop.arg) is ABinop and vop.arg.op == '+':
            vop = vop.arg # descent
            offset = isRegOffset(cls.regname, vop.arg1, vop.arg2)
            if type(offset) is int:
                if offset % 4 == 0:
                    offset = vop.arg2.number
                    return cls(offset)
            elif type(vop) is ASymbol and vop.name.upper() == self.regname:
                return cls(0)


class MemSpRel(MemRegXRel):
    regname = 'SP'


class MemR8Rel:
    def __init__(self, basereg, offset):
        assert type(basereg) is ArmReg
        self.basereg = basereg
        self.offset = offset

    def __repr__(self):
        return '[{}, #{}]'.format(self.basereg, self.offset)

    @classmethod
    def Create(cls, vop):
        if type(vop) is AUnop and vop.operation == '[]':
            vop = vop.arg # descent
            if type(vop) is ABinop:
                if vop.op == '+' and type(vop.arg1) is ASymbol and type(vop.arg2) is ANumber:
                    offset = vop.arg2.number
                    if offset > 120:
                        return
                    basereg = Reg8Op.Create(vop.arg1)
                    if not basereg:
                        return
                else:
                    return
            elif type(vop) is ASymbol:
                offset = 0
                basereg = Reg8Op.Create(vop)
                if not basereg:
                    return
            else:
                return
            return cls(getRegNum(basereg.num), offset)

class RegisterSet:
    def __init__(self, regs):
        assert type(regs) is set
        self.regs = regs

    def __repr__(self):
        return ','.join([str(r) for r in self.regs])

    @classmethod
    def Create(cls, vop):
        assert type(vop) is AUnop and vop.operation == '{}'
        assert type(vop.arg) is list
        regs = set()
        for arg in vop.arg:
            if type(arg) is ASymbol:
                reg = RegOp.Create(arg)
                if not reg:
                    return
                regs.add(reg)
            elif type(arg) is ABinop and arg.op == '-':
                reg1 = RegOp.Create(arg.arg1)
                reg2 = RegOp.Create(arg.arg2)
                if not reg1:
                    return
                if not reg2:
                    return
                for r in getRegisterRange(reg1, reg2):
                    regs.add(r)
            else:
                raise Exception('Cannot be')
        return cls(regs)

    def registerNumbers(self):
        return [r.num for r in self.regs]

# 8 bit registers:
r0 = ArmReg(0, 'r0')
armtarget.registers.append(r0)
r1 = ArmReg(1, 'r1')
armtarget.registers.append(r1)
r2 = ArmReg(2, 'r2')
armtarget.registers.append(r2)
r3 = ArmReg(3, 'r3')
armtarget.registers.append(r3)
r4 = ArmReg(4, 'r4')
armtarget.registers.append(r4)
r5 = ArmReg(5, 'r5')
armtarget.registers.append(r5)
r6 = ArmReg(6, 'r6')
armtarget.registers.append(r6)
r7 = ArmReg(7, 'r7')
armtarget.registers.append(r7)
# Other registers:
# TODO
sp = ArmReg(13, 'sp')
armtarget.registers.append(sp)
lr = ArmReg(14, 'lr')
armtarget.registers.append(lr)
pc = ArmReg(15, 'pc')
armtarget.registers.append(pc)


class ArmInstruction(Instruction):
    pass


@armtarget.instruction
class dcd_ins(ArmInstruction):
    mnemonic = 'dcd'
    operands = (Imm32,)
    def __init__(self, expr):
        if isinstance(expr, Imm32):
            self.expr = expr.imm
            self.label = None
        elif isinstance(expr, LabelRef):
            self.expr = 0
            self.label = expr
        else:
            raise NotImplementedError()

    def resolve(self, f):
        if self.label:
            self.expr = f(self.label.name)

    def encode(self):
        return u32(self.expr)

    def __repr__(self):
        return 'DCD 0x{0:X}'.format(self.expr)



# Memory related

class LS_imm5_base(ArmInstruction):
    """ ??? Rt, [Rn, imm5] """
    operands = (Reg8Op, MemR8Rel)
    def __init__(self, rt, memop):
        assert memop.offset % 4 == 0
        self.imm5 = memop.offset >> 2
        self.rn = memop.basereg.num
        self.rt = rt
        self.memloc = memop
        assert self.rn < 8
        assert self.rt.num < 8

    def encode(self):
        Rn = self.rn
        Rt = self.rt.num
        imm5 = self.imm5

        h = (self.opcode << 11) | (imm5 << 6) | (Rn << 3) | Rt
        return u16(h)

    def __repr__(self):
        return '{} {}, {}'.format(self.mnemonic, self.rt, self.memloc)

@armtarget.instruction
class storeimm5_ins(LS_imm5_base):
    mnemonic = 'STR'
    opcode = 0xC

@armtarget.instruction
class loadimm5_ins(LS_imm5_base):
    mnemonic = 'LDR'
    opcode = 0xD

class ls_sp_base_imm8(ArmInstruction):
    operands = (Reg8Op, MemSpRel)
    def __init__(self, rt, memop):
        self.rt = rt
        self.offset = memop.offset

    def encode(self):
        rt = self.rt.num
        assert rt < 8
        imm8 = self.offset >> 2
        assert imm8 < 256
        h = (self.opcode << 8) | (rt << 8) | imm8
        return u16(h)

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

def align(x, m):
    while ((x % m) != 0):
        x = x + 1
    return x

@armtarget.instruction
class ldr_pcrel(ArmInstruction):
    """ ldr Rt, LABEL, load value from pc relative position """
    mnemonic = 'ldr'
    operands = (RegOp, LabelRef)
    def __init__(self, rt, label):
        assert isinstance(label, LabelRef)
        self.rt = rt
        self.label = label
        self.offset = 0

    def resolve(self, f):
        la = f(self.label.name)
        sa = align(self.address + 2, 4)
        self.offset = (la - sa)
        if self.offset < 0:
            self.offset = 0

    def encode(self):
        rt = self.rt.num
        assert rt < 8
        imm8 = self.offset >> 2
        assert imm8 < 256
        assert imm8 >= 0
        h = (0x9 << 11) | (rt << 8) | imm8
        return u16(h)

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

@armtarget.instruction
class ldr_sprel(ls_sp_base_imm8):
    """ ldr Rt, [SP, imm8] """
    mnemonic = 'LDR'
    opcode = 0x98

@armtarget.instruction
class str_sprel(ls_sp_base_imm8):
    """ str Rt, [SP, imm8] """
    mnemonic = 'STR'
    opcode = 0x90

@armtarget.instruction
class mov_ins(ArmInstruction):
    """ mov Rd, imm8, move immediate value into register """
    mnemonic = 'mov'
    opcode = 4 # 00100 Rd(3) imm8
    operands = (RegOp, Imm8)
    def __init__(self, rd, imm):
        self.imm = imm.imm
        self.r = rd.num

    def encode(self):
        rd = self.r
        opcode = self.opcode
        imm8 = self.imm
        h = (opcode << 11) | (rd << 8) | imm8
        return u16(h)
    def __repr__(self):
        return 'MOV {0}, xx?'.format(self.r)





# Arithmatics:



class regregimm3_base(ArmInstruction):
    operands = (Reg8Op, Reg8Op, Imm3)
    def __init__(self, rd, rn, imm3):
        self.rd = rd
        self.rn = rn
        self.imm3 = imm3
    def encode(self):
        rd = self.rd.num
        rn = self.rn.num
        imm3 = self.imm3.imm
        opcode = self.opcode
        h = (self.opcode << 9) | (imm3 << 6) | (rn << 3) | rd
        return u16(h)


@armtarget.instruction
class addregregimm3_ins(regregimm3_base):
    """ add Rd, Rn, imm3 """
    mnemonic = 'add'
    opcode = 0b0001110


@armtarget.instruction
class subregregimm3_ins(regregimm3_base):
    """ sub Rd, Rn, imm3 """
    mnemonic = 'sub'
    opcode = 0b0001111


class regregreg_base(ArmInstruction):
    """ ??? Rd, Rn, Rm """
    operands = (Reg8Op, Reg8Op, Reg8Op)
    def __init__(self, rd, rn, rm):
        self.rd = rd
        self.rn = rn
        self.rm = rm
    def encode(self):
        rd = self.rd.num
        rn = self.rn.num
        rm = self.rm.num
        h = (self.opcode << 9) | (rm << 6) | (rn << 3) | rd
        return u16(h)
    def __repr__(self):
        return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.rm)

@armtarget.instruction
class addregs_ins(regregreg_base):
    mnemonic = 'ADD'
    opcode = 0b0001100

@armtarget.instruction
class subregs_ins(regregreg_base):
    mnemonic = 'SUB'
    opcode = 0b0001101


@armtarget.instruction
class movregreg_ext_ins(ArmInstruction):
    operands = (Reg16Op, Reg16Op)
    mnemonic = 'MOV'
    def __init__(self, rd, rm):
        self.rd = rd
        self.rm = rm
    def encode(self):
        Rd = self.rd.num & 0x7
        D = (self.rd.num >> 3) & 0x1
        Rm = self.rm.num
        opcode = 0b01000110
        return u16((opcode << 8) | (D << 7) |(Rm << 3) | Rd)
    def __repr__(self):
        return '{} {}, {}'.format(self.mnemonic, self.rd, self.rm)
        

@armtarget.instruction
class mulregreg_ins(ArmInstruction):
    """ mul Rn, Rdm """
    operands = (Reg8Op, Reg8Op)
    mnemonic = 'mul'
    def __init__(self, rn, rdm):
        self.rn = rn
        self.rdm = rdm
    def encode(self):
        rn = self.rn.num
        rdm = self.rdm.num
        opcode = 0b0100001101
        h = (opcode << 6) | (rn << 3) | rdm
        return u16(h)
    def __repr__(self):
        return '{} {}, {}'.format(self.mnemonic, self.rdn, self.rm)

class regreg_base(ArmInstruction):
    """ ??? Rdn, Rm """
    operands = (Reg8Op, Reg8Op)
    def __init__(self, rdn, rm):
        self.rdn = rdn
        self.rm = rm
    def encode(self):
        rdn = self.rdn.num
        rm = self.rm.num
        h = (self.opcode << 6) | (rm << 3) | rdn
        return u16(h)
    def __repr__(self):
        return '{} {}, {}'.format(self.mnemonic, self.rdn, self.rm)

@armtarget.instruction
class movregreg_ins(regreg_base):
    """ mov Rd, Rm """
    mnemonic = 'mov'
    opcode = 0

@armtarget.instruction
class andregs_ins(regreg_base):
    mnemonic = 'AND'
    opcode = 0b0100000000

@armtarget.instruction
class orrregs_ins(regreg_base):
    mnemonic = 'ORR'
    opcode = 0b0100001100

@armtarget.instruction
class cmp_ins(regreg_base):
    mnemonic = 'CMP'
    opcode = 0b0100001010

@armtarget.instruction
class lslregs_ins(regreg_base):
    mnemonic = 'LSL'
    opcode = 0b0100000010

@armtarget.instruction
class cmpregimm8_ins(ArmInstruction):
    """ cmp Rn, imm8 """
    mnemonic = 'cmp'
    opcode = 5 # 00101
    operands = (RegOp, Imm8)
    def __init__(self, rn, imm):
        self.rn = rn
        self.imm = imm
    def encode(self):
        rn = self.rn.num
        imm = self.imm.imm
        opcode = self.opcode
        h = (opcode << 11) | (rn << 8) | imm
        return u16(h)

# Jumping:

def wrap_negative(x, bits):
    b = struct.unpack('<I', struct.pack('<i', x))[0]
    mask = (1 << bits) - 1
    return b & mask

class jumpBase_ins(ArmInstruction):
    operands = (LabelRef,)
    def __init__(self, target_label):
        assert type(target_label) is LabelRef
        self.target = target_label
        self.offset = 0

    def resolve(self, f):
        la = f(self.target.name)
        sa = self.address + 4
        self.offset = (la - sa)
        #if self.offset < 0:
        #    # TODO: handle negative jump
        #    self.offset = 0

    def __repr__(self):
        return '{} {}'.format(self.mnemonic, self.target.name)

@armtarget.instruction
class b_ins(jumpBase_ins):
    mnemonic = 'B'
    def encode(self):
        imm11 = wrap_negative(self.offset >> 1, 11)
        h = (0b11100 << 11) | imm11 # | 1 # 1 to enable thumb mode
        return u16(h)

@armtarget.instruction
class bl_ins(jumpBase_ins):
    mnemonic = 'BL'
    def encode(self):
        imm32 = wrap_negative(self.offset >> 1, 32)
        imm11 = imm32 & 0x7FF
        imm10 = (imm32 >> 11) & 0x3FF
        j1 = 1 # TODO: what do these mean?
        j2 = 1
        s = (imm32 >> 24) & 0x1
        h1 = (0b11110 << 11) | (s << 10) | imm10 
        h2 = (0b1101 << 12) | (j1 << 13) | (j2 << 11) | imm11
        return u16(h1) + u16(h2)

class cond_base_ins(jumpBase_ins):
    def encode(self):
        imm8 = wrap_negative(self.offset >> 1, 8)
        h = (0b1101 << 12) | (self.cond << 8) | imm8
        return u16(h)


@armtarget.instruction
class beq_ins(cond_base_ins):
    mnemonic = 'beq'
    cond = 0


@armtarget.instruction
class bne_ins(cond_base_ins):
    mnemonic = 'bne'
    cond = 1


@armtarget.instruction
class blt_ins(cond_base_ins):
    mnemonic = 'blt'
    cond = 0b1011


@armtarget.instruction
class blt_ins(cond_base_ins):
    mnemonic = 'bgt'
    cond = 0b1100


@armtarget.instruction
class push_ins(ArmInstruction):
    operands = (RegisterSet,)
    mnemonic = 'push'
    def __init__(self, regs):
        assert (type(regs),) == self.operands, (type(regs),)
        self.regs = regs
    def __repr__(self):
        return '{0} {{{1}}}'.format(self.mnemonic, self.regs)
    def encode(self):
        reg_list = 0
        M = 0
        for n in self.regs.registerNumbers():
            if n < 8:
                reg_list |= (1 << n)
            elif n == 14:
                M = 1
            else:
                raise NotImplementedError('not implemented for this register')
        h = (0x5a << 9) | (M << 8) | reg_list
        return u16(h)

@armtarget.instruction
class pop_ins(ArmInstruction):
    operands = (RegisterSet,)
    mnemonic = 'pop'
    def __init__(self, regs):
        self.regs = regs
    def __repr__(self):
        return '{0} {{{1}}}'.format(self.mnemonic, self.regs)
    def encode(self):
        reg_list = 0
        P = 0
        for n in self.regs.registerNumbers():
            if n < 8:
                reg_list |= (1 << n)
            elif n == 15:
                P = 1
            else:
                raise NotImplementedError('not implemented for this register')
        h = (0x5E << 9) | (P << 8) | reg_list
        return u16(h)

@armtarget.instruction
class yield_ins(ArmInstruction):
    operands = ()
    mnemonic = 'yield'
    def encode(self):
        return u16(0xbf10)

# misc:

# add/sub SP:
@armtarget.instruction
class addspsp_ins(ArmInstruction):
    operands = (RegSpOp, RegSpOp, Imm7)
    mnemonic = 'add'
    def __init__(self, _sp, _sp2, imm7):
        self.imm7 = imm7.imm
        assert self.imm7 % 4 == 0
        self.imm7 >>= 2

    def encode(self):
        return u16((0b101100000 << 7) |self.imm7)

@armtarget.instruction
class subspsp_ins(ArmInstruction):
    operands = (RegSpOp, RegSpOp, Imm7)
    mnemonic = 'sub'
    def __init__(self, _sp, _sp2, imm7):
        self.imm7 = imm7.imm
        assert self.imm7 % 4 == 0
        self.imm7 >>= 2

    def encode(self):
        return u16((0b101100001 << 7) |self.imm7)

armtarget.check()