view python/target/msp430.py @ 306:b145f8e6050b

Start on c3 rewrite
author Windel Bouwman
date Mon, 09 Dec 2013 19:00:21 +0100
parents 534b94b40aa8
children 6f4753202b9a
line wrap: on
line source

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

# Create the target class (singleton):
msp430target = Target("MSP430")

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:
#########################

@msp430target.instruction
class reti_ins(MSP430Instruction):
    mnemonic = 'reti'
    operands = ()
    def encode(self):
        h = 0x1300
        return pack_ins(h)

class OneOpArith(MSP430Instruction):
    operands = (MSP430Reg, )
    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)

@msp430target.instruction
class jnz_ins(JumpInstruction):
    mnemonic = 'jnz'
    condition = 0

@msp430target.instruction
class jz_ins(JumpInstruction):
    mnemonic = 'jz'
    condition = 1

@msp430target.instruction
class jnc_ins(JumpInstruction):
    mnemonic = 'jnc'
    condition = 2

@msp430target.instruction
class jc_ins(JumpInstruction):
    mnemonic = 'jc'
    condition = 3

@msp430target.instruction
class jn_ins(JumpInstruction):
    mnemonic = 'jn'
    condition = 4

@msp430target.instruction
class jge_ins(JumpInstruction):
    mnemonic = 'jge'
    condition = 5

@msp430target.instruction
class jl_ins(JumpInstruction):
    mnemonic = 'jl'
    condition = 6

@msp430target.instruction
class jmp_ins(JumpInstruction):
    mnemonic = 'jmp'
    condition = 7

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


class TwoOpArith(MSP430Instruction):
    operands = (MSP430Operand, MSP430Operand)
    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)
    msp430target.addInstruction(ins_cls)

twoOpIns('mov', 4)

# This is equivalent to the helper function twoOpIns:
@msp430target.instruction
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)