Mercurial > lcfOS
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)