view python/target/msp430.py @ 341:4d204f6f7d4e devel

Rewrite of assembler parts
author Windel Bouwman
date Fri, 28 Feb 2014 18:07:14 +0100
parents 6f4753202b9a
children
line wrap: on
line source

from .basetarget import Register, Instruction, Target
from ppci.asmnodes import ASymbol, ANumber
from ppci import CompilerError
import struct
import types

# Create the target class (singleton):

class Msp430T(Target):
    def __init__(self):
        super().__init__('msp430')
        self.asm_keywords = []
        self.assembler_rules = []
        self.add_keyword('mov')
        self.add_keyword('r13')
        self.add_keyword('r14')
        self.add_keyword('r15')
        R0 = None # TODO
        self.add_rule('reg', ['r13'], lambda rhs: r13)
        self.add_rule('reg', ['r14'], lambda rhs: r14)
        self.add_rule('reg', ['r15'], lambda rhs: r15)
        self.add_instruction(['mov', 'reg', ',', 'reg'],
            lambda rhs: Mov(rhs[1], rhs[3]))
        
        self.add_keyword('reti')
        self.add_instruction(['reti'], lambda rhs: reti_ins())

msp430target = Msp430T()

REGISTER_MODE = 1
SYMBOLIC_MODE = 3
ABSOLUTE_MODE = 4
#TODO: add more modes!
IMMEDIATE_MODE = 7

# Target description for the MSP430 processor

class MSP430Reg(Register):
    def __init__(self, num, name):
        super().__init__(name)
        self.num = num

# 8 bit registers:
PCB = MSP430Reg(0, 'r0')
rpc = PCB
r11 = MSP430Reg(11, 'r11')
r12 = MSP430Reg(12, 'r12')
r13 = MSP430Reg(13, 'r13')
r14 = MSP430Reg(14, 'r14')
r15 = MSP430Reg(15, 'r15')

class MSP430Mem:
    pass

msp430target.registers.append(r11)
msp430target.registers.append(r12)
msp430target.registers.append(r13)
msp430target.registers.append(r14)
msp430target.registers.append(r15)

# .. etc

#GR8 = RegisterClass((PCB, R15B))

class MSP430Operand:
    def __init__(self, mode, param):
        self.mode = mode
        self.param = param
    def regField(self):
        if self.mode == REGISTER_MODE:
            return self.param
        elif self.mode == IMMEDIATE_MODE:
            return rpc.num
    def asField(self):
        if self.mode == REGISTER_MODE:
            return 0
        elif self.mode == IMMEDIATE_MODE:
            return 3
    def adField(self):
        if self.mode == REGISTER_MODE:
            return 0
        elif self.mode == IMMEDIATE_MODE:
            raise CompilerError('Cannot use immediate mode for destination operand')
    def extraBytes(self):
        if self.mode == IMMEDIATE_MODE:
            return pack_ins(self.param)
        return bytes()
    
    @classmethod
    def Create(cls, vop):
        if type(vop) is ASymbol:
            # try to map to register:
            regs = {}
            for r in msp430target.registers:
                regs[r.name] = r
            if vop.name in regs:
                reg = regs[vop.name]
                return cls(REGISTER_MODE, reg.num)
        elif type(vop) is ANumber:
            # Immediate mode:
            return cls(IMMEDIATE_MODE, vop.number)

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

class MSP430Instruction(Instruction):
    b = 0

class BInstruction:
    pass

class MSP430CoreInstruction(Instruction):
    pass

#########################
# Single operand arithmatic:
#########################

class reti_ins(MSP430Instruction):
    mnemonic = 'reti'
    def encode(self):
        h = 0x1300
        return pack_ins(h)

class OneOpArith(MSP430Instruction):
    def __init__(self, op1):
        self.op1 = op1

    def encode(self):
        # TODO:
        bits[15:10] = '00100'
        h1 = (self.opcode << 4)
        return pack_ins(h1)

def oneOpIns(mne, opc):
    """ Helper function to define a one operand arithmetic instruction """
    members = {'mnemonic': mne, 'opcode': opc}
    ins_cls = type(mne + '_ins', (OneOpArith,), members)
    msp430target.addInstruction(ins_cls)

oneOpIns('rrc', 0)
oneOpIns('swpb', 1)
oneOpIns('rra', 2)
oneOpIns('sxt', 3)
oneOpIns('push', 4)
oneOpIns('call', 5)

#########################
# Jump instructions:
#########################

class JumpInstruction(Instruction):
    def __init__(self, offset):
        self.offset = offset

    def encode(self):
        h = (1 << 13) | (self.condition << 10) | (self.offset)
        return pack_ins(h)

class jnz_ins(JumpInstruction):
    mnemonic = 'jnz'
    condition = 0

class jz_ins(JumpInstruction):
    mnemonic = 'jz'
    condition = 1

class jnc_ins(JumpInstruction):
    mnemonic = 'jnc'
    condition = 2

class jc_ins(JumpInstruction):
    mnemonic = 'jc'
    condition = 3

class jn_ins(JumpInstruction):
    mnemonic = 'jn'
    condition = 4

class jge_ins(JumpInstruction):
    mnemonic = 'jge'
    condition = 5

class jl_ins(JumpInstruction):
    mnemonic = 'jl'
    condition = 6

class jmp_ins(JumpInstruction):
    mnemonic = 'jmp'
    condition = 7

#########################
# Two operand arithmatic instructions:
#########################


class TwoOpArith(MSP430Instruction):
    def __init__(self, src, dst):
        self.op1 = src
        self.op2 = dst

    def encode(self):
        """
            Smart things have been done by MSP430 designers.
            As (2 bits) is the source addressing mode selector.
            Ad (1 bit) is the destination adressing mode selector.
            For the source there are 7 different addressing mode.
            For the destination there are 4.
            The trick is to use also the register to distuingish the
            different modes.
        """
        # TODO: Make memory also possible

        As = self.op1.asField() # addressing mode for the source
        Ad = self.op2.adField() # Addressing mode for dst
        b = self.b # When b=1, the operation is byte mode
        source = self.op1.regField()
        destination = self.op2.regField()
        h = (self.opcode << 12) | (source << 8)
        h |= (self.b << 6) | (As << 4) | (Ad << 7) | destination
        additions = self.op1.extraBytes() + self.op2.extraBytes()
        return pack_ins(h) + additions

    def decode(self, data):
        pass


def twoOpIns(mne, opc):
    """ Helper function to define a two operand arithmetic instruction """
    members = {'mnemonic': mne, 'opcode': opc}
    ins_cls = type(mne + '_ins', (TwoOpArith,), members)

class Mov(TwoOpArith):
    """ Adds the source to the destination """
    mnemonic = 'mov'
    opcode = 4

# This is equivalent to the helper function twoOpIns:
class add_ins(TwoOpArith):
    """ Adds the source to the destination """
    mnemonic = 'add'
    opcode = 5

    def operate(self):
        dst.value = dst.value + src.value
        setFlags()

twoOpIns('addc', 6)
twoOpIns('subc', 7)
twoOpIns('sub', 8)
twoOpIns('cmp', 9)
twoOpIns('dadd', 10)
twoOpIns('bit', 11)
twoOpIns('bic', 12)
twoOpIns('bis', 13)
twoOpIns('xor', 14)
twoOpIns('and', 15)