/* lkarea.c */ /* * Copyright (C) 1989-2009 Alan R. Baldwin * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * * Alan R. Baldwin * 721 Berkeley St. * Kent, Ohio 44240 */ /* * 02-Apr-98 JLH: add code to link 8051 data spaces */ #include "aslink.h" /*)Module lkarea.c * * The module lkarea.c contains the functions which * create and link together all area definitions read * from the .rel file(s). * * lkarea.c contains the following functions: * VOID lnkarea() * VOID lnksect() * VOID lkparea() * VOID newarea() * VOID setarea() * * lkarea.c contains no global variables. */ /*)Function VOID newarea() * * The function newarea() creates and/or modifies area * and areax structures for each A directive read from * the .rel file(s). The function lkparea() is called * to find the area structure associated with this name. * If the area does not yet exist then a new area * structure is created and linked to any existing * linked area structures. The area flags are copied * into the area flag variable. For each occurence of * an A directive an areax structure is created and * linked to the areax structures associated with this * area. The size of this area section is placed into * the areax structure. The flag value for all subsequent * area definitions for the same area are compared and * flagged as an error if they are not identical. * The areax structure created for every occurence of * an A directive is loaded with a pointer to the base * area structure and a pointer to the associated * head structure. And finally, a pointer to this * areax structure is loaded into the list of areax * structures in the head structure. Refer to lkdata.c * for details of the structures and their linkage. * * local variables: * areax **halp pointer to an array of pointers * a_uint i value * char id[] id string * int k counter, loop variable * int narea number of areas in this head structure * areax * taxp pointer to an areax structure * to areax structures * * global variables: * area *ap Pointer to the current * area structure * areax *axp Pointer to the current * areax structure * head *hp Pointer to the current * head structure * int lkerr error flag * * functions called: * a_uint eval() lkeval.c * VOID exit() c_library * int fprintf() c_library * VOID getid() lklex.c * VOID lkparea() lkarea.c * VOID skip() lklex.c * * side effects: * The area and areax structures are created and * linked with the appropriate head structures. * Failure to allocate area or areax structure * space will terminate the linker. Other internal * errors most likely caused by corrupted .rel * files will also terminate the linker. */ /* * Create an area entry. * * A xxxxxx size nnnn flags mm bank n * | | | | * | | | `-- ap->a_bank * | | `---------- ap->a_flag * | `--------------------- axp->a_size * `--------------------------------- ap->a_id * */ VOID newarea(void) { a_uint i; int k, narea; struct areax *taxp; struct areax **halp; char id[NCPS]; if (headp == NULL) { fprintf(stderr, "No header defined\n"); lkexit(ER_FATAL); } /* * Create Area entry */ getid(id, -1); lkparea(id); /* * Evaluate area size */ skip(-1); axp->a_size = eval(); /* * Evaluate flags */ skip(-1); i = 0; taxp = ap->a_axp; while (taxp->a_axp) { ++i; taxp = taxp->a_axp; } if (i == 0) { ap->a_flag = eval(); } else { i = eval(); if ((!is_sdld() || TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB) && i && (ap->a_flag != i)) { fprintf(stderr, "Conflicting flags in area %8s\n", id); lkerr++; } } if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB)) { /* * Evaluate area address */ skip(-1); axp->a_addr = eval(); } /* * Place pointer in header area list */ narea = hp->h_narea; halp = hp->a_list; for (k=0; k < narea ;++k) { if (halp[k] == NULL) { halp[k] = taxp; return; } } fprintf(stderr, "Header area list overflow\n"); lkexit(ER_FATAL); } /*)Function VOID lkparea(id) * * char * id pointer to the area name string * * The function lkparea() searches the linked area structures * for a name match. If the name is not found then an area * structure is created. An areax structure is created and * appended to the areax structures linked to the area structure. * The associated base area and head structure pointers are * loaded into the areax structure. * * local variables: * area * tap pointer to an area structure * areax * taxp pointer to an areax structure * * global variables: * area *ap Pointer to the current * area structure * area *areap The pointer to the first * area structure of a linked list * areax *axp Pointer to the current * areax structure * * functions called: * VOID * new() lksym() * char * strsto() lksym.c * int symeq() lksym.c * * side effects: * Area and/or areax structures are created. * Failure to allocate space for created structures * will terminate the linker. */ VOID lkparea(char *id) { struct area *tap; struct areax *taxp; ap = areap; axp = (struct areax *) new (sizeof(struct areax)); if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB)) axp->a_addr = -1; /* default: no address yet */ while (ap) { if (symeq(id, ap->a_id, 1)) { taxp = ap->a_axp; while (taxp->a_axp) taxp = taxp->a_axp; taxp->a_axp = axp; axp->a_bap = ap; axp->a_bhp = hp; return; } ap = ap->a_ap; } ap = (struct area *) new (sizeof(struct area)); if (areap == NULL) { areap = ap; } else { tap = areap; while (tap->a_ap) tap = tap->a_ap; tap->a_ap = ap; } ap->a_axp = axp; axp->a_bap = ap; axp->a_bhp = hp; ap->a_id = strsto(id); if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB)) ap->a_addr = 0; } /*)Function VOID lnkarea() * * The function lnkarea() resolves all area addresses. * The function evaluates each area structure (and all * the associated areax structures) in sequence. The * linking process supports four (4) possible area types: * * ABS/OVR - All sections (each individual areax * section) starts at the identical base * area address overlaying all other * areax sections for this area. The * size of the area is largest of the area * sections. * * ABS/CON - All sections (each individual areax * section) are concatenated with the * first section starting at the base * area address. The size of the area * is the sum of the section sizes. * * NOTE: Multiple absolute (ABS) areas are * never concatenated with each other, * thus absolute area A and absolute area * B will overlay each other if they begin * at the same location (the default is * always address 0 for absolute areas). * * REL/OVR - All sections (each individual areax * section) starts at the identical base * area address overlaying all other * areax sections for this area. The * size of the area is largest of the area * sections. * * REL/CON - All sections (each individual areax * section) are concatenated with the * first section starting at the base * area address. The size of the area * is the sum of the section sizes. * * NOTE: Relocatable (REL) areas are always concatenated * with each other, thus relocatable area B * (defined after area A) will follow * relocatable area A independent of the * starting address of area A. Within a * specific area each areax section may be * overlayed or concatenated with other * areax sections. * * * If a base address for an area is specified then the * area will start at that address. Any relocatable * areas defined subsequently will be concatenated to the * previous relocatable area if it does not have a base * address specified. * * The names s_ and l_ are created to * define the starting address and length of each area. * * local variables: * a_uint rloc ;current relocation address * char temp[] ;temporary string * struct symbol *sp ;symbol structure * * global variables: * area *ap Pointer to the current * area structure * area *areap The pointer to the first * area structure of a linked list * * functions called: * int fprintf() c_library * VOID lnksect() lkarea.c * symbol *lkpsym() lksysm.c * char * strncpy() c_library * int symeq() lksysm.c * * side effects: * All area and areax addresses and sizes are * determined and saved in their respective * structures. */ /* sdld6808 specific */ unsigned long codemap6808[2048]; /* end sdld6808 specific */ /* sdld specific */ VOID lnksect(struct area *tap); /* end sdld specific */ /* * Resolve all bank/area addresses. */ VOID lnkarea(void) { /* sdld specific */ a_uint rloc[4] = { 0, 0, 0, 0 }; int locIndex; /* end sdld specific */ /* sdld8051 & sdld6808 specific */ /*JCF: used to save the REG_BANK_[0-3] and SBIT_BYTES area pointers*/ struct area *ta[5]; int j; /* end sdld8051 & sdld6808 specific */ /* sdld6800 specific */ a_uint gs_size = 0; struct area *abs_ap = NULL; struct area *gs0_ap = NULL; /* end sdld6800 specific */ char temp[NCPS+2]; struct sym *sp; if (TARGET_IS_6808) { memset(codemap6808, 0, sizeof(codemap6808)); /* first sort all absolute areas to the front */ ap = areap; /* no need to check first area, it's in front anyway */ while (ap && ap->a_ap) { if (ap->a_ap->a_flag & A3_ABS) {/* next area is absolute, move it to front, reversed sequence is no problem for absolutes */ abs_ap = ap->a_ap; ap->a_ap = abs_ap->a_ap; abs_ap->a_ap = areap; areap = abs_ap; } else { ap = ap->a_ap; } } /* next accumulate all GSINITx/GSFINAL area sizes into GSINIT so they stay together */ ap = areap; while (ap) { if (!strncmp(ap->a_id, "GS", 2)) {/* GSxxxxx area */ if (ap->a_size == 0) { axp = ap->a_axp; while (axp) { ap->a_size += axp->a_size; axp = axp->a_axp; } } gs_size += ap->a_size; if (!strcmp(ap->a_id, "GSINIT0")) {/* GSINIT0 area */ gs0_ap = ap; } } ap = ap->a_ap; } if (gs0_ap) gs0_ap->a_size = gs_size; } ap = areap; while (ap) { if (ap->a_flag & A3_ABS) { /* * Absolute sections */ lnksect(ap); } else { /* sdld specific */ /* Determine memory space */ locIndex = 0; if ((TARGET_IS_8051)) { if (ap->a_flag & A_CODE) { locIndex = 1; } if (ap->a_flag & A_XDATA) { locIndex = 2; } if (ap->a_flag & A_BIT) { locIndex = 3; } } /* * Relocatable sections */ if (!is_sdld() || TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB) { if (ap->a_addr == 0) ap->a_addr = rloc[locIndex]; } else if (ap->a_bset == 0) { if ((TARGET_IS_6808 || TARGET_IS_STM8) && ap->a_flag & A_NOLOAD) { locIndex = 2; ap->a_addr = 0; } else { ap->a_addr = rloc[locIndex]; } ap->a_bset = 1; } lnksect(ap); rloc[ locIndex ] = ap->a_addr + ap->a_size; /* end sdld specific */ } /* * Create symbols called: * s_ the start address of the area * l_ the length of the area */ if (! symeq(ap->a_id, _abs_, 1)) { strcpy(temp+2, ap->a_id); *(temp+1) = '_'; *temp = 's'; sp = lkpsym(temp, 1); sp->s_addr = ap->a_addr; if (!is_sdld() || TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB) sp->s_axp = NULL; sp->s_type |= S_DEF; *temp = 'l'; sp = lkpsym(temp, 1); sp->s_addr = ap->a_size; sp->s_axp = NULL; sp->s_type |= S_DEF; } if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB)) { /*JCF: Since area BSEG is defined just before BSEG_BYTES, use the bit size of BSEG to compute the byte size of BSEG_BYTES: */ if (!strcmp(ap->a_id, "BSEG")) { if (TARGET_IS_8051) ap->a_ap->a_axp->a_size += ((ap->a_addr + ap->a_size + 7)/8); /*Bits to bytes*/ else ap->a_ap->a_axp->a_size=(ap->a_addr/8)+((ap->a_size+7)/8); /*Bits to bytes*/ } else if (!strcmp(ap->a_id, "REG_BANK_0")) ta[0]=ap; else if (!strcmp(ap->a_id, "REG_BANK_1")) ta[1]=ap; else if (!strcmp(ap->a_id, "REG_BANK_2")) ta[2]=ap; else if (!strcmp(ap->a_id, "REG_BANK_3")) ta[3]=ap; else if (!strcmp(ap->a_id, "BSEG_BYTES")) { ta[4]=ap; for(j=4; j>1; j--) { /*If upper register banks are not used roll back the relocation counter*/ if ( (ta[j]->a_size==0) && (ta[j-1]->a_size==0) ) { rloc[0]-=8; } else break; } } } ap = ap->a_ap; } } /* sdld specific */ static a_uint find_empty_space(a_uint start, a_uint size, char *id, unsigned long *map, unsigned int map_size) { a_uint i, j, k; unsigned long mask, b; map_size /= sizeof(*map); /* Convert from bytes to number of elements */ while (1) { a_uint a = start; i = start >> 5; j = (start + size) >> 5; mask = -(1 << (start & 0x1F)); if (j > map_size) { fprintf(stderr, "internal memory limit is exceeded for %s; memory size = 0x%06X, address = 0x%06X\n", id, map_size << 5, start + size - 1); break; } else { while (i < j) { if (map[i] & mask) { k = 32; for (b=0x80000000; b!=0; b>>=1, k--) { if (map[i] & b) break; } start = a + k; break; } i++; mask = 0xFFFFFFFF; a += 32; } if (start > a) continue; mask &= (1 << ((start + size) & 0x1F)) - 1; if (i < map_size && map[i] & mask) { k = 32; for (b=0x80000000; b!=0; b>>=1, k--) { if (map[i] & b) break; } start = (a & ~0x1F) + k; } if (start <= a) break; } } return start; } static a_uint allocate_space(a_uint start, a_uint size, char *id, unsigned long *map, unsigned int map_size) { a_uint i, j; unsigned long mask; a_uint a = start; i = start >> 5; j = (start + size) >> 5; mask = -(1 << (start & 0x1F)); map_size /= sizeof(*map); /* Convert from bytes to number of elements */ if (j > map_size) { fprintf(stderr, "internal memory limit is exceeded for %s; memory size = 0x%06X, address = 0x%06X\n", id, map_size << 5, start + size - 1); } else { while (i < j) { if (map[i] & mask) { fprintf(stderr, "memory overlap near 0x%X for %s\n", a, id); } map[i++] |= mask; mask = 0xFFFFFFFF; a += 32; } mask &= (1 << ((start + size) & 0x1F)) - 1; if (i < map_size && map[i] & mask) { fprintf(stderr, "memory overlap near 0x%X for %s\n", a, id); } map[i] |= mask; } return start; } /* end sdld specific */ /*)Function VOID lnksect(tap) * * area * tap pointer to an area structure * * The function lnksect() is the function called by * lnkarea() to resolve the areax addresses. Refer * to the function lnkarea() for more detail. Pageing * boundary and length errors will be reported by this * function. * * local variables: * a_uint size size of area * a_uint addr address of area * areax * taxp pointer to an areax structure * * global variables: * int lkerr error flag * * functions called: * none * * side effects: * All area and areax addresses and sizes are determined * and linked into the structures. */ VOID lnksect(struct area *tap) { a_uint size, addr; struct areax *taxp; size = 0; addr = tap->a_addr; taxp = tap->a_axp; if (tap->a_flag & A3_OVR) { /* * Overlayed sections */ while (taxp) { taxp->a_addr = addr; if (taxp->a_size > size) size = taxp->a_size; taxp = taxp->a_axp; } } else if (TARGET_IS_6808 && tap->a_flag & A3_ABS) { /* * Absolute sections */ while (taxp) { allocate_space(taxp->a_addr, taxp->a_size, tap->a_id, codemap6808, sizeof (codemap6808)); taxp->a_addr = 0; /* reset to zero so relative addresses become absolute */ size += taxp->a_size; taxp = taxp->a_axp; } } else { /* * Concatenated sections */ if (TARGET_IS_6808 && tap->a_size && !(ap->a_flag & A_NOLOAD)) { addr = find_empty_space(addr, tap->a_size, tap->a_id, codemap6808, sizeof (codemap6808)); } while (taxp) { /* find next unused address now */ if (TARGET_IS_6808 && taxp->a_size && !(ap->a_flag & A_NOLOAD)) { addr = find_empty_space(addr, taxp->a_size, tap->a_id, codemap6808, sizeof (codemap6808)); allocate_space(addr, taxp->a_size, tap->a_id, codemap6808, sizeof (codemap6808)); } taxp->a_addr = addr; addr += taxp->a_size; size += taxp->a_size; taxp = taxp->a_axp; } } tap->a_size = size; tap->a_addr = tap->a_axp->a_addr; for (taxp = tap->a_axp; taxp && !taxp->a_size; taxp = taxp->a_axp) { } if (taxp) { tap->a_addr = taxp->a_addr; } if ((tap->a_flag & A3_PAG) && (size > 256)) { fprintf(stderr, "\n?ASlink-Warning-Paged Area %s Length Error\n", tap->a_id); lkerr++; } if (TARGET_IS_8051 && (tap->a_flag & A3_PAG) && (tap->a_size) && ((tap->a_addr & 0xFFFFFF00) != ((addr-1) & 0xFFFFFF00))) { fprintf(stderr, "\n?ASlink-Warning-Paged Area %s Boundary Error\n", tap->a_id); lkerr++; } } /*)Function VOID setarea() * * The function setarea() scans the base address lines in the * basep structure, evaluates the arguments, and sets the beginning * address of the specified areas. * * local variables: * a_uint v expression value * char id[] base id string * * global variables: * area *ap Pointer to the current * area structure * area *areap The pointer to the first * area structure of a linked list * base *basep The pointer to the first * base structure * base *bsp Pointer to the current * base structure * char *ip pointer into the REL file * text line in ib[] * int lkerr error flag * * functions called: * a_uint expr() lkeval.c * int fprintf() c_library * VOID getid() lklex.c * int getnb() lklex.c * int symeq() lksym.c * * side effects: * The base address of an area is set. */ VOID setarea(void) { a_uint v; char id[NCPS]; bsp = basep; while (bsp) { ip = bsp->b_strp; getid(id, -1); if (getnb() == '=') { v = expr(0); for (ap = areap; ap != NULL; ap = ap->a_ap) { if (symeq(id, ap->a_id, 1)) break; } if (ap == NULL) { fprintf(stderr, "ASlink-Warning-No definition of area %s\n", id); lkerr++; } else { ap->a_addr = v; ap->a_bset = 1; } } else { fprintf(stderr, "ASlink-Warning-No '=' in base expression"); lkerr++; } bsp = bsp->b_base; } } /* sdld specific */ a_uint lnksect2 (struct area *tap, int locIndex); unsigned long codemap8051[524288]; unsigned long xdatamap[131216]; struct area *dseg_ap = NULL; a_uint dram_start = 0; a_uint iram_start = 0; /*Modified version of the functions for packing variables in internal data memory*/ VOID lnkarea2 (void) { a_uint rloc[4]={0, 0, 0, 0}; a_uint gs_size = 0; int locIndex; char temp[NCPS+2]; struct sym *sp; int j; struct area *bseg_ap = NULL; struct area *abs_ap = NULL; struct area *gs0_ap = NULL; struct sym *sp_dseg_s=NULL, *sp_dseg_l=NULL; memset(idatamap, ' ', 256); memset(codemap8051, 0, sizeof(codemap8051)); memset(xdatamap, 0, sizeof(xdatamap)); /* first sort all absolute areas to the front */ ap = areap; /* no need to check first area, it's in front anyway */ while (ap && ap->a_ap) { if (ap->a_ap->a_flag & A3_ABS) {/* next area is absolute, move it to front, reversed sequence is no problem for absolutes */ abs_ap = ap->a_ap; ap->a_ap = abs_ap->a_ap; abs_ap->a_ap = areap; areap = abs_ap; } else { ap = ap->a_ap; } } /* next accumulate all GSINITx/GSFINAL area sizes into GSINIT so they stay together */ ap = areap; abs_ap = areap; while (ap) { if (ap->a_flag & A3_ABS) { abs_ap = ap; /* Remember the last abs area */ } if (!strncmp(ap->a_id, "GS", 2)) {/* GSxxxxx area */ if (ap->a_size == 0) { axp = ap->a_axp; while (axp) { ap->a_size += axp->a_size; axp = axp->a_axp; } } gs_size += ap->a_size; if (!strcmp(ap->a_id, "GSINIT0")) {/* GSINIT0 area */ gs0_ap = ap; } } /*Since area BSEG is defined just before BSEG_BYTES, use the bit size of BSEG to compute the byte size of BSEG_BYTES: */ else if (!strcmp(ap->a_id, "BSEG")) { bseg_ap = ap->a_ap; //BSEG_BYTES for (axp=ap->a_axp; axp; axp=axp->a_axp) ap->a_size += axp->a_size; bseg_ap->a_axp->a_size = ((ap->a_addr + ap->a_size + 7)/8); /*Bits to bytes*/ ap->a_ap = bseg_ap->a_ap; //removed BSEG_BYTES from list bseg_ap->a_ap = abs_ap->a_ap; abs_ap->a_ap = bseg_ap; //inserted BSEG_BYTES after abs bseg_ap = ap; //BSEG } else if (!strcmp(ap->a_id, "DSEG")) { dseg_ap = ap; /*Need it later*/ dram_start = ap->a_addr; } else if (!strcmp(ap->a_id, "ISEG")) { iram_start = ap->a_addr; } ap = ap->a_ap; } if (gs0_ap) gs0_ap->a_size = gs_size; ap = areap; while (ap) { /* Determine memory space */ if (ap->a_flag & A_CODE) locIndex = 1; else if (ap->a_flag & A_XDATA) locIndex = 2; else if (ap->a_flag & A_BIT) locIndex = 3; else locIndex = 0; if (ap->a_flag & A3_ABS) /* Absolute sections */ { lnksect2(ap, locIndex); } else /* Relocatable sections */ { if (ap->a_bset == 0) { ap->a_addr = rloc[locIndex]; ap->a_bset = 1; } rloc[locIndex] = lnksect2(ap, locIndex); } if (!strcmp(ap->a_id, "BSEG_BYTES") && (ap->a_axp->a_addr >= 0x20)) { bseg_ap->a_addr += (ap->a_axp->a_addr - 0x20) * 8; /*Bytes to bits*/ } /* * Create symbols called: * s_ the start address of the area * l_ the length of the area */ if (! symeq(ap->a_id, _abs_, 1)) { strcpy(temp+2,ap->a_id); *(temp+1) = '_'; *temp = 's'; sp = lkpsym(temp, 1); sp->s_addr = ap->a_addr; sp->s_type |= S_DEF; if (!strcmp(ap->a_id, "DSEG")) sp_dseg_s=sp; *temp = 'l'; sp = lkpsym(temp, 1); sp->s_addr = ap->a_size; sp->s_axp = NULL; sp->s_type |= S_DEF; if (!strcmp(ap->a_id, "DSEG")) sp_dseg_l=sp; } ap = ap->a_ap; } /*Compute the size of DSEG*/ if(dseg_ap!=NULL) { dseg_ap->a_addr=0; dseg_ap->a_size=0; for(j=0; j<0x80; j++) if(idatamap[j]!=' ') dseg_ap->a_size++; } if(sp_dseg_s!=NULL) sp_dseg_s->s_addr=0; if(sp_dseg_l!=NULL) sp_dseg_l->s_addr=dseg_ap->a_size; } a_uint lnksect2 (struct area *tap, int locIndex) { a_uint size, addr; struct areax *taxp; int j, k, ramlimit, ramstart; char fchar=' ', dchar='a'; char ErrMsg[]="?ASlink-Error-Could not get %d consecutive byte%s" " in internal RAM for area %s.\n"; tap->a_unaloc=0; /*Notice that only ISEG and SSEG can be in the indirectly addressable internal RAM*/ if( (!strcmp(tap->a_id, "ISEG")) || (!strcmp(tap->a_id, "SSEG")) ) { ramstart = iram_start; if ((iram_size <= 0) || (ramstart + iram_size > 0x100)) ramlimit = 0x100; else ramlimit = ramstart + iram_size; } else { ramstart = dram_start; if ((iram_size <= 0) || (ramstart + iram_size > 0x80)) ramlimit = 0x80; else ramlimit = ramstart + iram_size; } size = 0; addr = tap->a_addr; taxp = tap->a_axp; /*Use a letter to identify each area in the internal RAM layout map*/ if (locIndex==0) { /**/ if(!strcmp(tap->a_id, "DSEG")) fchar='D'; /*It will be converted to letters 'a' to 'z' later for each areax*/ else if(!strcmp(tap->a_id, "ISEG")) fchar='I'; else if(!strcmp(tap->a_id, "SSEG")) fchar='S'; else if(!strcmp(tap->a_id, "OSEG")) fchar='Q'; else if(!strcmp(tap->a_id, "REG_BANK_0")) fchar='0'; else if(!strcmp(tap->a_id, "REG_BANK_1")) fchar='1'; else if(!strcmp(tap->a_id, "REG_BANK_2")) fchar='2'; else if(!strcmp(tap->a_id, "REG_BANK_3")) fchar='3'; else if(!strcmp(tap->a_id, "BSEG_BYTES")) fchar='B'; else if(!strcmp(tap->a_id, "BIT_BANK")) fchar='T'; else fchar=' ';/*???*/ } else if (locIndex == 1) { /**/ if(!strcmp(tap->a_id, "GSINIT")) fchar='G'; } else if (locIndex == 2) { /**/ if(!strcmp(tap->a_id, "XSTK")) fchar='K'; } if (tap->a_flag & A3_OVR) /* Overlayed sections */ { while (taxp) { if(taxp->a_size == 0) { taxp = taxp->a_axp; continue; } if ( (fchar=='0')||(fchar=='1')||(fchar=='2')||(fchar=='3') ) /*Reg banks*/ { addr=(fchar-'0')*8; taxp->a_addr=addr; size=taxp->a_size; for(j=addr; (j<(int)(addr+size)) && (ja_size=0; j(int)taxp->a_size) taxp->a_size=k; } else { k=0; } } stacksize=taxp->a_size; } /*If more space required, release the previously allocated areax in internal RAM and search for a bigger one*/ if((int)taxp->a_size>size) { size=(int)taxp->a_size; for(j=ramstart; ja_size) break; } /*Mark the memory used for overlay*/ if(k==(int)taxp->a_size) { addr = j-k+1; for(j=addr; (j<(int)(addr+size)); j++) idatamap[j]=fchar; } else /*Couldn't find a chunk big enough: report the problem.*/ { tap->a_unaloc=taxp->a_size; fprintf(stderr, ErrMsg, taxp->a_size, taxp->a_size>1?"s":"", tap->a_id); lkerr++; } /* avoid redundant processing SSEG */ if (fchar == 'S') break; } } else if (fchar=='T') /*Bit addressable bytes in internal RAM*/ { /*Find the size of the space currently used for this areax overlay*/ // for(j=0x20, size=0; j<0x30; j++) // if(idatamap[j]==fchar) size++; /*If more space required, release the previously allocated areax in internal RAM and search for a bigger one*/ if((int)taxp->a_size>size) { size=(int)taxp->a_size; for(j=0x20; j<0x30; j++) if(idatamap[j]==fchar) idatamap[j]=' '; /*Search for a space large enough in data memory for this overlay areax*/ for(j=0x20, k=0; j<0x30; j++) { if(idatamap[j]==' ') k++; else k=0; if(k==(int)taxp->a_size) break; } /*Mark the memory used for overlay*/ if(k==(int)size) { addr = j-k+1; for(j=addr; (j<(int)(addr+size)); j++) idatamap[j]=fchar; } else /*Couldn't find a chunk big enough: report the problem.*/ { tap->a_unaloc=taxp->a_size; fprintf(stderr, ErrMsg, taxp->a_size, taxp->a_size>1?"s":"", tap->a_id); lkerr++; } } } else /*Overlay areas not in internal ram*/ { taxp->a_addr = addr; if (taxp->a_size > size) size = taxp->a_size; } taxp = taxp->a_axp; } /*Now set all overlayed areax to the same start address*/ taxp = tap->a_axp; while (taxp) { taxp->a_addr = addr; taxp = taxp->a_axp; } } else if (tap->a_flag & A3_ABS) /* Absolute sections */ { while (taxp) { if (locIndex == 0) { for (j=taxp->a_addr; (j<(int)(taxp->a_addr+taxp->a_size)) && (j<256); j++) { if (idatamap[j] == ' ') idatamap[j] = 'A'; else fprintf(stderr, "memory overlap at 0x%X for %s\n", j, tap->a_id); } } else if (locIndex == 1) { allocate_space(taxp->a_addr, taxp->a_size, tap->a_id, codemap8051, sizeof (codemap8051)); } else if (locIndex == 2) { allocate_space(taxp->a_addr, taxp->a_size, tap->a_id, xdatamap, sizeof (xdatamap)); } taxp->a_addr = 0; /* reset to zero so relative addresses become absolute */ size += taxp->a_size; taxp = taxp->a_axp; } } else /* Concatenated sections */ { if ((locIndex == 1) && tap->a_size) { addr = find_empty_space(addr, tap->a_size, tap->a_id, codemap8051, sizeof (codemap8051)); } if ((locIndex == 2) && tap->a_size) { addr = find_empty_space(addr, tap->a_size, tap->a_id, xdatamap, sizeof (xdatamap)); } while (taxp) { if (taxp->a_size) { if( (fchar=='D') || (fchar=='I') ) { /*Search for a space large enough in internal RAM for this areax*/ for(j=ramstart, k=0; ja_size) break; } if(k==(int)taxp->a_size) { taxp->a_addr = j-k+1; size += taxp->a_size; for(j=taxp->a_addr; (j<(int)(taxp->a_addr+taxp->a_size)) && (ja_size>0)&&(fchar=='D'))dchar++; if((dchar<'a')||(dchar>'z')) dchar='D'; /*Ran out of letters?*/ } else /*We are in trouble, there is not enough memory for an areax chunk*/ { taxp->a_addr = addr; addr += taxp->a_size; size += taxp->a_size; tap->a_unaloc+=taxp->a_size; fprintf(stderr, ErrMsg, taxp->a_size, taxp->a_size>1?"s":"", tap->a_id); lkerr++; } } else if (fchar=='B') { /*Search for a space large enough in data memory for this areax*/ for(j=0x20, k=0; j<0x30; j++) { if(idatamap[j]==' ') k++; else k=0; if(k==(int)taxp->a_size) break; } /*Mark the memory used*/ if(k==(int)taxp->a_size) { taxp->a_addr = j-k+1; for(j=taxp->a_addr; (j<(int)(taxp->a_addr+taxp->a_size)) && (j<0x30); j++) idatamap[j]=fchar; } else /*Couldn't find a chunk big enough: report the problem.*/ { tap->a_unaloc=taxp->a_size; fprintf(stderr, ErrMsg, taxp->a_size, taxp->a_size>1?"s":"", tap->a_id); lkerr++; } size += taxp->a_size; } else /*For concatenated BIT, CODE, and XRAM areax's*/ { //expand external stack if((fchar=='K') && (taxp->a_size == 1)) { taxp->a_size = 256-(addr & 0xFF); } //find next unused address now if (locIndex == 1) { addr = find_empty_space(addr, taxp->a_size, tap->a_id, codemap8051, sizeof (codemap8051)); allocate_space(addr, taxp->a_size, tap->a_id, codemap8051, sizeof (codemap8051)); } if (locIndex == 2) { addr = find_empty_space(addr, taxp->a_size, tap->a_id, xdatamap, sizeof (xdatamap)); allocate_space(addr, taxp->a_size, tap->a_id, xdatamap, sizeof (xdatamap)); } taxp->a_addr = addr; addr += taxp->a_size; size += taxp->a_size; } } else { taxp->a_addr = addr; } taxp = taxp->a_axp; } } tap->a_size = size; tap->a_addr = tap->a_axp->a_addr; for (taxp = tap->a_axp; taxp && !taxp->a_size; taxp = taxp->a_axp) { } if (taxp) { tap->a_addr = taxp->a_addr; } if ((tap->a_flag & A3_PAG) && (size > 256)) { fprintf(stderr, "\n?ASlink-Warning-Paged Area %s Length Error\n", tap->a_id); lkerr++; } if ((tap->a_flag & A3_PAG) && (tap->a_size) && ((tap->a_addr & 0xFFFFFF00) != ((addr-1) & 0xFFFFFF00))) { fprintf(stderr, "\n?ASlink-Warning-Paged Area %s Boundary Error\n", tap->a_id); lkerr++; } return addr; } /* end sdld specific */