compact_rel.c 3.56 KB
/*==============================================================================    
    Module: compact_rel.c
    $Revision: 1.1.1.2 $
    $Date: 2002/10/29 08:07:15 $
    $Author: blythe $
    $Source: /root/leakn64/depot/rf/sw/bbplayer/tools/gcord/com/compact_rel.c,v $

    Procedures pulled out from libmld and modified.
    These procedures are clean of obj structure.
==============================================================================*/

#include <compact_reloc.h>
#include <string.h>
#include <malloc.h>

#include "global.h"

static unsigned alloc_cm_rel_sz = 2048;

static char	*cm_rel_head;
static unsigned cm_rel_size;
static unsigned cm_rel_count;

void new_cr_header(char *start, size_t size)
{
	cm_rel_head = (char *) malloc(alloc_cm_rel_sz);
	memcpy(cm_rel_head, start, size);
	cm_rel_size = size;
}

char *cr_head(void)
{
	return cm_rel_head;
}

unsigned cr_size(void)
{
	return cm_rel_size;
}

void add_cr(int type,
		unsigned long offset,
		unsigned long dist2lo,
		unsigned long vaddr)
{
    union cm_rlc *cr;
    char *p;
    long delta;
    static unsigned long prev_vaddr = 0;

    if (cm_rel_head == (char *) NULL)
    {
	cm_rel_head = (char *) malloc(alloc_cm_rel_sz);
    }
    else if((cm_rel_size + sizeof(union cm_rlc)) > alloc_cm_rel_sz)
    {
	alloc_cm_rel_sz *=2;
	cm_rel_head = (char *) realloc(cm_rel_head, alloc_cm_rel_sz);
    }
    if (cm_rel_head == (char *) NULL)
	error("Out of Memory doing compact relocation\n");

    cr =  (union cm_rlc *)(cm_rel_head + cm_rel_size);

    cr->r.type = type;
    delta = (vaddr-prev_vaddr) >> 2;
    if (VADDR_OVFL(delta)) 
    {
	delta = 0;
	cr->r.addend |= ADDEND_BASE;
    }
    cr->r.del_vaddr = VADDR_DELTA(delta);

    cr->r.del_lo = dist2lo >> 2;

    if (offset)
    {
	cr->r.addend |= ADDEND_CONST;
	cr->c.addend_const = offset;
	if (cr->r.addend & ADDEND_BASE)
	    cr->cb.base = vaddr;
    }
    else
    {
	cr->r.addend |= ADDEND_NOCONST;
	if (cr->r.addend & ADDEND_BASE)
	    cr->b.base = vaddr;
    }
    cm_rel_count++;
    cm_rel_size += sizeof(struct COMPACT_RELOC);
    cm_rel_size += ((cr->r.addend & ADDEND_BASE)!=0) * sizeof(unsigned);
    cm_rel_size += ((cr->r.addend & ADDEND_CONST)!=0) * sizeof(unsigned);
    prev_vaddr = vaddr;
}

void cm_rlc_reset(cm_struct *cm)
{
    ASSERT(cm);
    ASSERT(cm->rlc_ptr);
    cm->cur_rlc_ptr = cm->rlc_ptr;
    cm->cur_rlc_no = 0;
    cm->last_base = 0;
}


int cm_rlc_get(cm_struct *cm)
{
union cm_rlc *p_cm_rlc;
unsigned size = 0;

    ASSERT(cm);
    ASSERT(cm->cur_rlc_ptr);
    if (cm->cur_rlc_no == cm->rlc_no) 
    {
        cm->cur_rlc_ptr = (char *)0;
        return 0;
    }

    p_cm_rlc = (union cm_rlc *)cm->cur_rlc_ptr;
    cm->rlc_entry.type = p_cm_rlc->r.type;
    cm->rlc_entry.dist2lo = (unsigned)(p_cm_rlc->r.del_lo << 2);
    cm->rlc_entry.vaddr = (unsigned)(p_cm_rlc->r.del_vaddr << 2);

    if (p_cm_rlc->r.addend & ADDEND_CONST) 
    {
        cm->rlc_entry.konst = p_cm_rlc->c.addend_const;
        size += sizeof(unsigned);
        if (p_cm_rlc->r.addend & ADDEND_BASE) 
	{
            cm->rlc_entry.vaddr = p_cm_rlc->cb.base;
            size += sizeof(unsigned);
        }
        else
            cm->rlc_entry.vaddr += cm->last_base;
    }
    else 
    {
        if (p_cm_rlc->r.addend & ADDEND_BASE) 
	{
            size +=sizeof(unsigned);
            cm->rlc_entry.vaddr += p_cm_rlc->b.base;
        }
        else
            cm->rlc_entry.vaddr += cm->last_base;
    }
    cm->cur_rlc_ptr += (unsigned)(size + sizeof(struct COMPACT_RELOC));
    cm->last_base = cm->rlc_entry.vaddr;
    cm->cur_rlc_no++;
    ASSERT(cm->cur_rlc_no <= cm->rlc_no);
    return 1;
}