All pastes #494287 Raw Edit

Unnamed

public text v1 · immutable
·published 2007-05-18 04:43 UTC
rendered paste body
#!/usr/bin/python
# -*- coding: iso-8859-15 -*-

import intelhex

program_is_depressed = False

class ProgramContentsError(Exception):
    pass

class RelocatePIC18(object):
    def __init__(self, device):
        self.device = device
    
    def _make_goto(self, target):
        if target&1 == 1:
            raise ValueError("Goto target must be even: 0x%X"%target)
        target >>= 1
        if target > 0xFFFFF:
            raise ValueError("Target too large for goto: 0x%X"%target)
        w0 = 0xEF00 | ((target)&0xFF)
        w1 = 0xF000 | (target>>8)
        return [w0, w1]
    
    # we consider goto and call here
    def _is_goto(self, word):
        return word & 0xFF00 in (0xEC00,0xED00,0xEF00)
    
    def _get_goto_target(self, words):
        if not self._is_goto(words[0]):
            raise ValueError("Instruction is not a goto derivative: 0x%04X"%words[0])
        if words[1] & 0xF000 != 0xF000:
            raise ValueError("Goto derivative has invalid second word: 0x%04X"%(words[1]))
        return ((words[0] & 0x00FF) | ((words[1]&0x0FFF)<<8))<<1
    
    def _patch_goto(self, words, target):
        self._get_goto_target(words) #validate
        w0 = words[0] & 0xFF00
        w1 = words[1] & 0xF000
        if target&1 == 1:
            raise ValueError("Goto target must be even: 0x%X"%target)
        target >>= 1
        if target > 0xFFFFF:
            raise ValueError("Target too large for goto: 0x%X"%target)
        w0 |= ((target)&0xFF)
        w1 |= (target>>8)
        return [w0, w1]
    
    # convert a 2's-complement number to a python int
    def _sign_extend(self, num, signmask):
        base = num & (~signmask)
        sign = num & signmask == signmask
        if sign:
            return base - signmask
        return base
    
    # note: we consider rcall to be a subtype of bra for our purposes
    def _is_bra(self, word):
        return word & 0xF800 in (0xE000,0xD000,0xD800)
    
    def _get_bra_target(self, word, address):
        if word & 0xF800 == 0xE000:
            n = self._sign_extend(word & 0x00FF,0x0080)
        elif word & 0xF800 in (0xD000,0xD800):
            n = self._sign_extend(word & 0x07FF,0x0400)
        else:
            raise ValueError("Instruction is not a branch derivative: 0x%04X"%word)
        return address + 2 * n + 2
    
    def _make_bra(self, target, template, address):
        if address & 1 == 1:
            raise ValueError("Branch address must be even: 0x%X"%address)
        if target & 1 == 1:
            raise ValueError("Branch target must be even: 0x%X"%target)
        n = (target - address - 2)/2

        if template & 0xF800 == 0xE000:
            if not -0x80 <= n < 0x80:
                raise ValueError("Branch target out of range: 0x%X (n=0x%Xtemplate=0x%04X)"%(target,n,template))
            return (template & 0xFF00) | (n & 0x00FF)
        elif template & 0xF800 in (0xD000,0xD800):
            if not -0x400 <= n < 0x400:
                raise ValueError("Branch target out of range: 0x%X (n=0x%X,template=0x%04X)"%(target,n,template))
            return (template & 0xF800) | (n & 0x07FF)
        else:
            raise ValueError("Template must be a branch derivative: 0x%04X"%word)
    
    def _relocate_target_if_needed(self, target):
        if self.device.reset_vector <= target < self.device.reset_vector+self.device.reset_vector_size:
            target = target - self.device.reset_vector + self.device.relocation_reset
        if self.do_interrupt:
            if self.device.interrupt_vector <= target < self.device.interrupt_vector+self.device.interrupt_vector_size:
                target = target - self.device.interrupt_vector + self.device.relocation_interrupt
        return target
    def _relocate_vector(self, data16, start, size, target, patchtarget = None):
        
        # sigh (note that this is sort of fixed now - unset program_is_depressed)
        if program_is_depressed and self._is_goto(data16[start+size-self.device.word_size]):
            print """


Hi there, it's me, the bootloader program.
You know what, I'm sick of this.
Coding around random crap when patching the vectors is a pain in the rear.
Now you have a goto in the middle of the end boundary of the vector.
Do you even know what you've done?
It's people like you that create the world's problems.
Yeah, I could replace it with a branch and put it in the branch table.
You know what? I don't care.
What was supposed to be a simple ten-line relocation has turned into a 250-line monster.
That's not counting the constant database in devices.py.
I'm depressed now. It's 7am and I'm still working on this.
I'm raising an exception now.
You get to fix this one.
See you later.


Hola, soy yo, el bootloader.
¿Sabes que? Estoy harto de todo esto.
Escribir código para controlar todos estos casos raros cuando parcheo los vectores es un coñazo.
Ahora tienes un goto en medio del borde del vector.
¿Acaso sabes lo que has hecho?
La gente como tu sois los que causais los problemas de este mundo.
Si, si, podria reemplazarlo por un branch y ponerlo en la tabla.
¿Sabes que? No me importa.
Esto se suponía que iba a ser una tontería de 10 lineas, y ahora es un monstruo de 250.
Eso sin contar la base de datos de constantes en devices.py.
Ahora estoy deprimido. Son las 7am y todavía ando trabajando en esto.
Voy a lanzar una excepción ahora.
Te toca a ti arreglar el problema esta vez.
Nos vemos.
"""
            raise Exception("Program is depressed")
        
        # copy vector
        for addr in xrange(0,size,2):
            data16[target+addr] = data16[start+addr]
        
        r_end = target+size
        gs = self.device.goto_size
        ws = self.device.word_size
        gws = gs//ws
        
        # add continuation gotos
        data16[r_end : r_end+gs] = self._make_goto(self._relocate_target_if_needed(start+size))
        data16[r_end+gs : r_end+2*gs] = self._make_goto(self._relocate_target_if_needed(start+size+ws))
        
        # fix embedded gotos in target vector
        for addr in xrange(0,size-ws,2):
            if self._is_goto(data16[target+addr]):
                old_target = self._get_goto_target(data16[target+addr:target+addr+gs])
                new_target = self._relocate_target_if_needed(old_target)
                if old_target != new_target:
                    data16[target+addr:target+addr+gs] = self._patch_goto(data16[target+addr:target+addr+gs], new_target)
        
        
        if patchtarget != None:
            
            bt = self.device.relocation_branch_table
            bte = self.device.relocation_branch_table_entries
            
            # add entries to branch table and patch target vector
            for addr in xrange(0,size,2):
                if self._is_bra(data16[start+addr]):
                    tg = self._get_bra_target(data16[start+addr],start+addr)
                    tg = self._relocate_target_if_needed(tg)
                    try:
                        data16[target+addr] = self._make_bra(tg,data16[start+addr],target+addr)
                    except ValueError,e:
                        if not "out of range" in e.args[0]:
                            raise e
                        if self.bti >= bte:
                            raise ProgramContentsError("Too many branches in vectors (max %d)"%bte)
                        data16[bt+self.bti*gs:bt+self.bti*gs+gs] = self._make_goto(tg)
                        data16[target+addr] = self._make_bra(bt+self.bti*gs,data16[start+addr],target+addr)
                        self.bti += 1

            
            # fix a possible goto at the end of the source using the branch table
            if self._is_goto(data16[start+size-ws]):
                word = data16[start+size-ws] & 0xFF00
                if word == 0xEC00:
                    bra_tpl = 0xD800
                elif word == 0xED00:
                    bra_tpl = None
                elif word == 0xEF00:
                    bra_tpl = 0xD000
                tg = self._get_goto_target(data16[start+size-ws:start+size-ws+gs])
                tg = self._relocate_target_if_needed(tg)
                if bra_tpl != None:
                    try:
                        data16[target+size-ws] = self._make_bra(tg,bra_tpl,target+size-ws)
                    except ValueError,e:
                        if not "out of range" in e.args[0]:
                            raise e
                        if self.bti >= bte:
                            raise ProgramContentsError("Too many branches in vectors (max %d) (this branch autogenerated due to broken goto)"%bte)
                        data16[bt+self.bti*gs:bt+self.bti*gs+gs] = self._patch_goto(data16[start+size-ws:start+size-ws+gs],tg)
                        data16[target+size-ws] = self._make_bra(bt+self.bti*gs,0xD000,target+size-ws)
                        self.bti += 1
                else:
                    if self.bti >= bte:
                        raise ProgramContentsError("Too many branches in vectors (max %d)"%bte)
                    data16[bt+self.bti*gs:bt+self.bti*gs+gs] = self._patch_goto(data16[start+size-ws:start+size-ws+gs],tg)
                    data16[target+size-ws] = self._make_bra(bt+self.bti*gs,0xD000,target+size-ws)
                    self.bti += 1
                    
                
            
            # fix embedded gotos in original vector too
            for addr in xrange(0,size,2):
                if self._is_goto(data16[start+addr]):
                    old_target = self._get_goto_target(data16[start+addr:start+addr+gs])
                    new_target = self._relocate_target_if_needed(old_target)
                    if old_target != new_target:
                        data16[start+addr:start+addr+gs] = self._patch_goto(data16[start+addr:start+addr+gs], new_target)
            
            # finally, patch original vector
            data16[start:start+gs] = self._make_goto(patchtarget)
    
    def relocate(self, data, do_interrupt = False):
        data16 = intelhex.IntelHex16bit(data)
        data16.padding = 0x0000 #nop
        
        self.bti = 0
        
        self.do_interrupt = do_interrupt
        
        # relocate reset vector
        self._relocate_vector(data16,
            self.device.reset_vector,
            self.device.reset_vector_size,
            self.device.relocation_reset,
            self.device.bootloader_reset)
        
        patch_interrupt = None
        if do_interrupt:
            patch_interrupt = self.device.bootloader_interrupt
        
        # relocate interrupt vector
        self._relocate_vector(data16,
            self.device.interrupt_vector,
            self.device.interrupt_vector_size,
            self.device.relocation_interrupt,
            patch_interrupt)