From: epetrich Date: Wed, 15 Oct 2003 05:46:28 +0000 (+0000) Subject: Initial import X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=badb689faae2cb5c930988943c5fd4c73922525c;p=fw%2Fsdcc Initial import git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@2941 4a8a32a2-be11-0410-ad9d-d568d2c75423 --- diff --git a/as/hc08/Makefile.as_hc08 b/as/hc08/Makefile.as_hc08 new file mode 100644 index 00000000..1edad3d5 --- /dev/null +++ b/as/hc08/Makefile.as_hc08 @@ -0,0 +1,62 @@ +CC=gcc +LEX=flex +YACC=bison +INCROOT=. +CFLAGS=-ggdb -O2 -I $(INCROOT) +TARGETS=$(SDCCDIR)/bin/as_hc08 +ALLOBJECTS= asmain.o aslex.o assym.o assubr.o asnoice.o \ + asexpr.o asdata.o aslist.o asout.o asstore.o \ + h08ext.o h08pst.o h08mch.o h08adr.o strcmpi.o + +all:: $(TARGETS) + +clean:: + rm -f $(TARGETS) $(ALLOBJECTS) + +asmain.o : asmain.c asm.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o asmain.o asmain.c + +aslex.o : aslex.c asm.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o aslex.o aslex.c + +assym.o : assym.c asm.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o assym.o assym.c + +assubr.o : assubr.c asm.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o assubr.o assubr.c + +asexpr.o : asexpr.c asm.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o asexpr.o asexpr.c + +asdata.o : asdata.c asm.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o asdata.o asdata.c + +aslist.o : aslist.c asm.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o aslist.o aslist.c + +asout.o : asout.c asm.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o asout.o asout.c + +asnoice.o : asnoice.c asm.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o asnoice.o asnoice.c + +asstore.o : asstore.c asm.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o asstore.o asstore.c + +h08ext.o : h08ext.c asm.h m6808.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o h08ext.o h08ext.c + +h08pst.o : h08pst.c asm.h m6808.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o h08pst.o h08pst.c + +h08mch.o : h08mch.c asm.h m6808.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o h08mch.o h08mch.c + +h08adr.o : h08adr.c asm.h m6808.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o h08adr.o h08adr.c + +strcmpi.o : strcmpi.c strcmpi.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o strcmpi.o strcmpi.c + +$(TARGETS): $(ALLOBJECTS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(ALLOBJECTS) diff --git a/as/hc08/Makefile.aslink b/as/hc08/Makefile.aslink new file mode 100644 index 00000000..0aebe56e --- /dev/null +++ b/as/hc08/Makefile.aslink @@ -0,0 +1,68 @@ +CC=gcc +LEX=flex +YACC=bison +INCROOT=. +CFLAGS=-ggdb -O2 -I $(INCROOT) +TARGETS=$(SDCCDIR)/bin/aslink +ALLOBJECTS= lkmain.o lkhead.o lkarea.o lkdata.o\ + lkeval.o lklex.o lksym.o lkrloc.o\ + lklibr.o lklist.o lkihx.o lks19.o\ + lkstore.o lknoice.o lkmem.o lkaomf51.o strcmpi.o +all:: $(TARGETS) + +clean:: + rm -f $(TARGETS) $(ALLOBJECTS) + +lkmain.o : lkmain.c aslink.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o lkmain.o lkmain.c + +lkhead.o : lkhead.c aslink.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o lkhead.o lkhead.c + +lkarea.o : lkarea.c aslink.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o lkarea.o lkarea.c + +lkdata.o : lkdata.c aslink.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o lkdata.o lkdata.c + +lkeval.o : lkeval.c aslink.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o lkeval.o lkeval.c + +lklex.o : lklex.c aslink.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o lklex.o lklex.c + +lksym.o : lksym.c aslink.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o lksym.o lksym.c + +lkrloc.o : lkrloc.c aslink.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o lkrloc.o lkrloc.c + +lklibr.o : lklibr.c aslink.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o lklibr.o lklibr.c + +lklist.o : lklist.c aslink.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o lklist.o lklist.c + +lkihx.o : lkihx.c aslink.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o lkihx.o lkihx.c + +lks19.o : lks19.c aslink.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o lks19.o lks19.c + +lkstore.o : lkstore.c aslink.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o lkstore.o lkstore.c + +lknoice.o : lknoice.c aslink.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o lknoice.o lknoice.c + +strcmpi.o : strcmpi.c strcmpi.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o strcmpi.o strcmpi.c + +lkmem.o : lkmem.c aslink.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o lkmem.o lkmem.c + +lkaomf51.o : lkaomf51.c aslink.h + $(CC) $(CFLAGS) $(LDFLAGS) -c -o lkaomf51.o lkaomf51.c + +$(TARGETS): $(ALLOBJECTS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(ALLOBJECTS) diff --git a/as/hc08/Makefile.bcc b/as/hc08/Makefile.bcc new file mode 100644 index 00000000..b30978c4 --- /dev/null +++ b/as/hc08/Makefile.bcc @@ -0,0 +1,25 @@ +# Makefile for Borlad C++ + +PRJDIR = ../.. + +!include $(PRJDIR)/Bcc.inc + +ASOBJECTS = asmain.obj aslex.obj assym.obj assubr.obj asnoice.obj \ + asexpr.obj asdata.obj aslist.obj asout.obj asstore.obj \ + h08ext.obj h08pst.obj h08mch.obj h08adr.obj strcmpi.obj + +LKOBJECTS = lkmain.obj lkhead.obj lkarea.obj lkdata.obj \ + lkeval.obj lklex.obj lksym.obj lkrloc.obj \ + lklibr.obj lklist.obj lkihx.obj lks19.obj \ + lkstore.obj lknoice.obj lkmem.obj lkaomf51.obj strcmpi.obj + +ASX8051 = $(PRJDIR)/bin/asx8051.exe +ASLINK = $(PRJDIR)/bin/aslink.exe + +all: $(ASX8051) $(ASLINK) + +$(ASX8051): $(ASOBJECTS) + $(CC) $(CFLAGS) -e$@ $(ASOBJECTS) + +$(ASLINK): $(LKOBJECTS) + $(CC) $(CFLAGS) -e$@ $(LKOBJECTS) diff --git a/as/hc08/Makefile.in b/as/hc08/Makefile.in new file mode 100644 index 00000000..c7d7a0e8 --- /dev/null +++ b/as/hc08/Makefile.in @@ -0,0 +1,116 @@ +# +# +# + +VERSION = @VERSION@ +VERSIONHI = @VERSIONHI@ +VERSIONLO = @VERSIONLO@ +VERSIONP = @VERSIONP@ + +SHELL = /bin/sh +CC = @CC@ +CPP = @CPP@ +INSTALL = @INSTALL@ +STRIP = @STRIP@ + +PRJDIR = ../.. + +srcdir = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +libdir = @libdir@ +datadir = @datadir@ +includedir = @includedir@ +mandir = @mandir@ +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +infodir = @info@ + +EXEEXT = @EXEEXT@ + +CPPFLAGS = @CPPFLAGS@ -I. -I$(PRJDIR) +CFLAGS = @CFLAGS@ -Wall +M_OR_MM = @M_OR_MM@ +LDFLAGS = @LDFLAGS@ + +ASOBJECTS = asmain.o aslex.o assym.o assubr.o asnoice.o \ + asexpr.o asdata.o aslist.o asout.o asstore.o \ + h08ext.o h08pst.o h08mch.o h08adr.o strcmpi.o +ASSOURCES = $(patsubst %.o,%.c,$(ASOBJECTS)) + +LKOBJECTS = lkmain.o lkhead.o lkarea.o lkdata.o \ + lkeval.o lklex.o lksym.o lkrloc.o \ + lklibr.o lklist.o lkihx.o lks19.o \ + lkstore.o lknoice.o lkmem.o lkaomf51.o strcmpi.o +LKSOURCES = $(patsubst %.o,%.c,$(LKOBJECTS)) + +ASX8051 = $(PRJDIR)/bin/as-hc08$(EXEEXT) +ASLINK = $(PRJDIR)/bin/link-hc08$(EXEEXT) + +transform = @program_transform_name@ + +# Compiling entire program or any subproject +# ------------------------------------------ +all: checkconf $(ASX8051) $(ASLINK) + +$(ASX8051): $(ASOBJECTS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(ASOBJECTS) + +$(ASLINK): $(LKOBJECTS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(LKOBJECTS) + +# Compiling and installing everything and runing test +# --------------------------------------------------- +install: all installdirs + $(INSTALL) $(ASX8051) `echo $(bindir)/asx8051$(EXEEXT)|sed '$(transform)'` + $(STRIP) `echo $(bindir)/as-hc08$(EXEEXT)|sed '$(transform)'` + $(INSTALL) $(ASLINK) `echo $(bindir)/aslink$(EXEEXT)|sed '$(transform)'` + $(STRIP) `echo $(bindir)/link-hc08$(EXEEXT)|sed '$(transform)'` + +# Deleting all the installed files +# -------------------------------- +uninstall: + rm -f $(bindir)/as-hc08$(EXEEXT) $(bindir)/link-hc08$(EXEEXT) + + +# Performing self-test +# -------------------- +check: + + +# Performing installation test +# ---------------------------- +installcheck: + + +# Creating installation directories +# --------------------------------- +installdirs: + $(INSTALL) -d $(bindir) + + +# Creating dependencies +# --------------------- +dep: Makefile.dep + +Makefile.dep: $(ASSOURCES) $(LKSOURCES) *.h $(PRJDIR)/*.h + $(CPP) $(CPPFLAGS) $(M_OR_MM) $(ASSOURCES) $(LKSOURCES) >Makefile.dep + +include Makefile.dep +include clean.mk + +# My rules +# -------- +.c.o: + $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< + + +# Remaking configuration +# ---------------------- +checkconf: + @if [ -f $(PRJDIR)/devel ]; then\ + $(MAKE) -f conf.mk srcdir="$(srcdir)" PRJDIR="$(PRJDIR)" freshconf;\ + fi + +# End of Makefile diff --git a/as/hc08/alloc.h b/as/hc08/alloc.h new file mode 100644 index 00000000..dd404a86 --- /dev/null +++ b/as/hc08/alloc.h @@ -0,0 +1,4 @@ +/* alloc.h */ +/* DECUS C */ + +#include diff --git a/as/hc08/asdata.c b/as/hc08/asdata.c new file mode 100644 index 00000000..16657520 --- /dev/null +++ b/as/hc08/asdata.c @@ -0,0 +1,289 @@ +/* asdata.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + * + * 28-Oct-97 JLH: + * - change s_id from [NCPS] to pointer (comment) + * 2-Nov-97 JLH: + * - add jflag for debug control + */ + +#include +#include +#include +#include "asm.h" + +/*)Module asdata.c + * + * The module asdata.c contains the global constants, + * structures, and variables used in the assembler. + */ + +int aserr; /* ASxxxx error counter + */ +jmp_buf jump_env; /* compiler dependent structure + * used by setjmp() and longjmp() + */ +int inpfil; /* count of assembler + * input files specified + */ +int incfil; /* current file handle index + * for include files + */ +int cfile; /* current file handle index + * of input assembly files + */ +int flevel; /* IF-ELSE-ENDIF flag will be non + * zero for false conditional case + */ +int tlevel; /* current conditional level + */ +int ifcnd[MAXIF+1]; /* array of IF statement condition + * values (0 = FALSE) indexed by tlevel + */ +int iflvl[MAXIF+1]; /* array of IF-ELSE-ENDIF flevel + * values indexed by tlevel + */ + +char afn[PATH_MAX]; /* afile temporary file name + */ +char srcfn[MAXFIL][PATH_MAX]; /* array of source file names + */ +int srcline[MAXFIL]; /* source line number + */ +char incfn[MAXINC][PATH_MAX]; /* array of include file names + */ +int incline[MAXINC]; /* include line number + */ + +int radix; /* current number conversion radix: + * 2 (binary), 8 (octal), 10 (decimal), + * 16 (hexadecimal) + */ +int line; /* current assembler source + * line number + */ +int page; /* current page number + */ +int lop; /* current line number on page + */ +int pass; /* assembler pass number + */ +int lflag; /* -l, generate listing flag + */ +int cflag; /* -lc, generate sdcdb debug info + */ +int gflag; /* -g, make undefined symbols global flag + */ +int aflag; /* -a, make all symbols global flag + */ +int jflag; /* -j, generate debug information flag + */ +int oflag; /* -o, generate relocatable output flag + */ +int sflag; /* -s, generate symbol table flag + */ +int pflag; /* -p, enable listing pagination + */ +int xflag; /* -x, listing radix flag + */ +int fflag; /* -f(f), relocations flagged flag + */ +Addr_T laddr; /* address of current assembler line + * or value of .if argument + */ +Addr_T fuzz; /* tracks pass to pass changes in the + * address of symbols caused by + * variable length instruction formats + */ +int lmode; /* listing mode + */ +char *ep; /* pointer into error list + * array eb[NERR] + */ +char eb[NERR]; /* array of generated error codes + */ +char *ip; /* pointer into the assembler-source + * text line in ib[] + */ +char ib[NINPUT]; /* assembler-source text line + */ +char *cp; /* pointer to assembler output + * array cb[] + */ +char cb[NCODE]; /* array of assembler output values + */ +int *cpt; /* pointer to assembler relocation type + * output array cbt[] + */ +int cbt[NCODE]; /* array of assembler relocation types + * describing the data in cb[] + */ +char tb[NTITL]; /* Title string buffer + */ +char stb[NSBTL]; /* Subtitle string buffer + */ +char optsdcc[NINPUT]; /* sdcc compile options + */ +int flat24Mode; /* non-zero if we are using DS390 24 bit + * flat mode (via .flat24 directive). + */ + +char symtbl[] = { "Symbol Table" }; +char aretbl[] = { "Area Table" }; + +char module[NCPS]; /* module name string + */ + +/* + * The mne structure is a linked list of the assembler + * mnemonics and directives. The list of mnemonics and + * directives contained in the device dependent file + * xxxpst.c are hashed and linked into NHASH lists in + * module assym.c by syminit(). The structure contains + * the mnemonic/directive name, a subtype which directs + * the evaluation of this mnemonic/directive, a flag which + * is used to detect the end of the mnemonic/directive + * list in xxxpst.c, and a value which is normally + * associated with the assembler mnemonic base instruction + * value. + * + * struct mne + * { + * struct mne *m_mp; Hash link + * char m_id[NCPS]; Mnemonic + * char m_type; Mnemonic subtype + * char m_flag; Mnemonic flags + * Addr_T m_valu; Value + * }; + */ +struct mne *mnehash[NHASH]; + +/* + * The sym structure is a linked list of symbols defined + * in the assembler source files. The first symbol is "." + * defined here. The entry 'struct tsym *s_tsym' + * links any temporary symbols following this symbol and + * preceeding the next normal symbol. The structure also + * contains the symbol's name, type (USER or NEW), flag + * (global, assigned, and multiply defined), a pointer + * to the area structure defining where the symbol is + * located, a reference number assigned by outgsd() in + * asout.c, and the symbols address relative to the base + * address of the area where the symbol is located. + * + * struct sym + * { + * struct sym *s_sp; Hash link + * struct tsym *s_tsym; Temporary symbol link + * char *s_id; Symbol (JLH) + * char s_type; Symbol subtype + * char s_flag; Symbol flags + * struct area *s_area; Area line, 0 if absolute + * int s_ref; Ref. number + * Addr_T s_addr; Address + * }; + */ +struct sym sym[] = { + {NULL, NULL, ".", S_USER, S_END, NULL, 0, 0} +}; + +struct sym *symp; /* pointer to a symbol structure + */ +struct sym *symhash[NHASH]; /* array of pointers to NHASH + * linked symbol lists + */ + +/* + * The area structure contains the parameter values for a + * specific program or data section. The area structure + * is a linked list of areas. The initial default area + * is "_CODE" defined here, the next area structure + * will be linked to this structure through the structure + * element 'struct area *a_ep'. The structure contains the + * area name, area reference number ("_CODE" is 0) determined + * by the order of .area directives, area size determined + * from the total code and/or data in an area, area fuzz is + * an variable used to track pass to pass changes in the + * area size caused by variable length instruction formats, + * and area flags which specify the area's relocation type. + * + * struct area + * { + * struct area *a_ap; Area link + * char a_id[NCPS]; Area Name + * int a_ref; Reference number + * Addr_T a_size; Area size + * Addr_T a_fuzz; Area fuzz + * int a_flag; Area flags + * }; + */ +struct area area[] = { + {NULL, "_CODE", 0, 0, 0, A_CON|A_REL} +}; + +struct area *areap; /* pointer to an area structure + */ + +FILE *lfp; /* list output file handle + */ +FILE *ofp; /* relocation output file handle + */ +FILE *tfp; /* symbol table output file handle + */ +FILE *sfp[MAXFIL]; /* array of assembler-source file handles + */ +FILE *ifp[MAXINC]; /* array of include-file file handles + */ + +/* + * array of character types, one per + * ASCII character + */ +unsigned char ctype[128] = { +/*NUL*/ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, +/*BS*/ ILL, SPACE, ILL, ILL, SPACE, ILL, ILL, ILL, +/*DLE*/ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, +/*CAN*/ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, +/*SPC*/ SPACE, ETC, ETC, ETC, LETTER, BINOP, BINOP, ETC, +/*(*/ ETC, ETC, BINOP, BINOP, ETC, BINOP, LETTER, BINOP, +/*0*/ DGT2, DGT2, DGT8, DGT8, DGT8, DGT8, DGT8, DGT8, +/*8*/ DGT10, DGT10, ETC, ETC, BINOP, ETC, BINOP, ETC, +/*@*/ ETC, LTR16, LTR16, LTR16, LTR16, LTR16, LTR16, LETTER, +/*H*/ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/*P*/ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/*X*/ LETTER, LETTER, LETTER, ETC, ETC, ETC, BINOP, LETTER, +/*`*/ ETC, LTR16, LTR16, LTR16, LTR16, LTR16, LTR16, LETTER, +/*h*/ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/*p*/ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/*x*/ LETTER, LETTER, LETTER, ETC, BINOP, ETC, ETC, ETC +}; + +/* + * an array of characters which + * perform the case translation function + */ +char ccase[128] = { +/*NUL*/ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', +/*BS*/ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', +/*DLE*/ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', +/*CAN*/ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', +/*SPC*/ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', +/*(*/ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', +/*0*/ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', +/*8*/ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', +/*@*/ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', +/*H*/ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', +/*P*/ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', +/*X*/ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', +/*`*/ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', +/*h*/ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', +/*p*/ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', +/*x*/ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177' +}; diff --git a/as/hc08/asexpr.c b/as/hc08/asexpr.c new file mode 100644 index 00000000..26aea4b0 --- /dev/null +++ b/as/hc08/asexpr.c @@ -0,0 +1,711 @@ + /* asexpr.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +#include +#include "asm.h" + +/*)Module asexpr.c + * + * The module asexpr.c contains the routines to evaluate + * arithmetic/numerical expressions. The functions in + * asexpr.c perform a recursive evaluation of the arithmetic + * expression read from the assembler-source text line. + * The expression may include binary/unary operators, brackets, + * symbols, labels, and constants in hexadecimal, decimal, octal + * and binary. Arithmetic operations are prioritized and + * evaluated by normal arithmetic conventions. + * + * asexpr.c contains the following functions: + * VOID abscheck() + * Addr_T absexpr() + * VOID clrexpr() + * int digit() + * VOID expr() + * int oprio() + * VOID term() + * + * asexpr.c contains no local/static variables + */ + +/*)Function VOID expr(esp, n) + * + * expr * esp pointer to an expr structure + * int n a firewall priority; all top + * level calls (from the user) + * should be made with n set to 0. + * + * The function expr() evaluates an expression and + * stores its value and relocation information into + * the expr structure supplied by the user. + * + * local variables: + * int c current assembler-source + * text character + * int p current operator priority + * area * ap pointer to an area structure + * exp re internal expr structure + * + * global variables: + * char ctype[] array of character types, one per + * ASCII character + * + * functions called: + * VOID abscheck() asexpr.c + * VOID clrexpr() asexpr.c + * VOID expr() asexpr.c + * int getnb() aslex.c + * int oprio() asexpr.c + * VOID qerr() assubr.c + * VOID rerr() assubr.c + * VOID term() asexpr.c + * VOID unget() aslex.c + * + * + * side effects: + * An expression is evaluated modifying the user supplied + * expr structure, a sym structure maybe created for an + * undefined symbol, and the parse of the expression may + * terminate if a 'q' error occurs. + */ + +VOID +expr(esp, n) +register struct expr *esp; +int n; +{ + register int c, p; + struct area *ap; + struct expr re; + + term(esp); + while (ctype[c = getnb()] & BINOP) { + /* + * Handle binary operators + - * / & | % ^ << >> + */ + if ((p = oprio(c)) <= n) + break; + if ((c == '>' || c == '<') && c != get()) + qerr(); + clrexpr(&re); + expr(&re, p); + esp->e_rlcf |= re.e_rlcf; + if (c == '+') { + /* + * esp + re, at least one must be absolute + */ + if (esp->e_base.e_ap == NULL) { + /* + * esp is absolute (constant), + * use area from re + */ + esp->e_base.e_ap = re.e_base.e_ap; + } else + if (re.e_base.e_ap) { + /* + * re should be absolute (constant) + */ + rerr(); + } + if (esp->e_flag && re.e_flag) + rerr(); + if (re.e_flag) + esp->e_flag = 1; + esp->e_addr += re.e_addr; + } else + if (c == '-') { + /* + * esp - re + */ + if ((ap = re.e_base.e_ap) != NULL) { + if (esp->e_base.e_ap == ap) { + esp->e_base.e_ap = NULL; + } else { + rerr(); + } + } + if (re.e_flag) + rerr(); + esp->e_addr -= re.e_addr; + } else { + /* + * Both operands (esp and re) must be constants + */ + /* SD :- moved the abscheck to each case + case and change the right shift operator.. if + right shift by 8 bits of a relocatable address then + the user wants the higher order byte. set the R_MSB + for the expression */ + switch (c) { + + case '*': + abscheck(esp); + abscheck(&re); + esp->e_addr *= re.e_addr; + break; + + case '/': + abscheck(esp); + abscheck(&re); + esp->e_addr /= re.e_addr; + break; + + case '&': + abscheck(esp); + abscheck(&re); + esp->e_addr &= re.e_addr; + break; + + case '|': + abscheck(esp); + abscheck(&re); + esp->e_addr |= re.e_addr; + break; + + case '%': + abscheck(esp); + abscheck(&re); + esp->e_addr %= re.e_addr; + break; + + case '^': + abscheck(esp); + abscheck(&re); + esp->e_addr ^= re.e_addr; + break; + + case '<': + abscheck(esp); + abscheck(&re); + esp->e_addr <<= re.e_addr; + break; + + case '>': + /* SD change here */ + abscheck(&re); + /* if the left is a relative address & + the right side is == 8 then */ + if (esp->e_base.e_ap && re.e_addr == 8) { + esp->e_rlcf |= R_MSB ; + break; + } + else if (esp->e_base.e_ap && re.e_addr == 16) + { + if (flat24Mode) + { + esp->e_rlcf |= R_HIB; + } + else + { + warnBanner(); + fprintf(stderr, + "(expr >> 16) is only meaningful in " + ".flat24 mode.\n"); + qerr(); + } + + break; + } + /* else continue with the normal processing */ + abscheck(esp); + esp->e_addr >>= re.e_addr; + break; + + default: + qerr(); + break; + } + } + } + unget(c); +} + +/*)Function Addr_T absexpr() + * + * The function absexpr() evaluates an expression, verifies it + * is absolute (i.e. not position dependent or relocatable), and + * returns its value. + * + * local variables: + * expr e expr structure + * + * global variables: + * none + * + * functions called: + * VOID abscheck() asexpr.c + * VOID clrexpr() asexpr.c + * VOID expr() asexpr.c + * + * side effects: + * If the expression is not absolute then + * a 'r' error is reported. + */ + +Addr_T +absexpr() +{ + struct expr e; + + clrexpr(&e); + expr(&e, 0); + abscheck(&e); + return (e.e_addr); +} + +/*)Function VOID term(esp) + * + * expr * esp pointer to an expr structure + * + * The function term() evaluates a single constant + * or symbol value prefaced by any unary operator + * ( +, -, ~, ', ", >, or < ). This routine is also + * responsible for setting the relocation type to symbol + * based (e.flag != 0) on global references. + * + * local variables: + * int c current character + * char id[] symbol name + * char * jp pointer to assembler-source text + * int n constant evaluation running sum + * int r current evaluation radix + * sym * sp pointer to a sym structure + * tsym * tp pointer to a tsym structure + * int v current digit evaluation + * + * global variables: + * char ctype[] array of character types, one per + * ASCII character + * sym * symp pointer to a symbol structure + * + * functions called: + * VOID abscheck() asexpr.c + * int digit() asexpr.c + * VOID err() assubr.c + * VOID expr() asexpr.c + * int is_abs() asexpr.c + * int get() aslex.c + * VOID getid() aslex.c + * int getmap() aslex.c + * int getnb() aslex.c + * sym * lookup() assym.c + * VOID qerr() assubr.c + * VOID unget() aslex.c + * + * side effects: + * An arithmetic term is evaluated, a symbol structure + * may be created, term evaluation may be terminated + * by a 'q' error. + */ + +VOID +term(esp) +register struct expr *esp; +{ + register int c, n; + register char *jp; + char id[NCPS]; + struct sym *sp; + struct tsym *tp; + int r=0, v; + + c = getnb(); + /* + * Discard the unary '+' at this point and + * also any reference to numerical arguments + * associated with the '#' prefix. + */ + while (c == '+' || c == '#') { c = getnb(); } + /* + * Evaluate all binary operators + * by recursively calling expr(). + */ + if (c == LFTERM) { + expr(esp, 0); + if (getnb() != RTTERM) + qerr(); + return; + } + if (c == '-') { + expr(esp, 100); + abscheck(esp); + esp->e_addr = 0-esp->e_addr; + return; + } + if (c == '~') { + expr(esp, 100); + abscheck(esp); + esp->e_addr = ~esp->e_addr; + return; + } + if (c == '\'') { + esp->e_mode = S_USER; + esp->e_addr = getmap(-1)&0377; + return; + } + if (c == '\"') { + esp->e_mode = S_USER; + if (hilo) { + esp->e_addr = (getmap(-1)&0377)<<8; + esp->e_addr |= (getmap(-1)&0377); + } else { + esp->e_addr = (getmap(-1)&0377); + esp->e_addr |= (getmap(-1)&0377)<<8; + } + return; + } + if (c == '>' || c == '<') { + expr(esp, 100); + if (is_abs (esp)) { + /* + * evaluate msb/lsb directly + */ + if (c == '>') + esp->e_addr >>= 8; + esp->e_addr &= 0377; + return; + } else { + /* + * let linker perform msb/lsb, lsb is default + */ + esp->e_rlcf |= R_BYT2; + if (c == '>') + esp->e_rlcf |= R_MSB; + return; + } + } + /* + * Evaluate digit sequences as local symbols + * if followed by a '$' or as constants. + */ + if (ctype[c] & DIGIT) { + esp->e_mode = S_USER; + jp = ip; + while (ctype[(int)*jp] & RAD10) { + jp++; + } + if (*jp == '$') { + n = 0; + while ((v = digit(c, 10)) >= 0) { + n = 10*n + v; + c = get(); + } + tp = symp->s_tsym; + while (tp) { + if (n == tp->t_num) { + esp->e_base.e_ap = tp->t_area; + esp->e_addr = tp->t_addr; + return; + } + tp = tp->t_lnk; + } + /* err('u'); */ + return; + } + r = radix; + if (c == '0') { + c = get(); + switch (c) { + case 'b': + case 'B': + r = 2; + c = get(); + break; + case 'o': + case 'O': + case 'q': + case 'Q': + r = 8; + c = get(); + break; + case 'd': + case 'D': + r = 10; + c = get(); + break; + case 'h': + case 'H': + case 'x': + case 'X': + r = 16; + c = get(); + break; + default: + break; + } + } + n = 0; + while ((v = digit(c, r)) >= 0) { + n = r*n + v; + c = get(); + } + unget(c); + esp->e_addr = n; + return; + } + /* + * Evaluate '$' sequences as a temporary radix + * if followed by a '%', '&', '#', or '$'. + */ + if (c == '$') { + c = get(); + if (c == '%' || c == '&' || c == '#' || c == '$') { + switch (c) { + case '%': + r = 2; + break; + case '&': + r = 8; + break; + case '#': + r = 10; + break; + case '$': + r = 16; + break; + default: + break; + } + c = get(); + n = 0; + while ((v = digit(c, r)) >= 0) { + n = r*n + v; + c = get(); + } + unget(c); + esp->e_mode = S_USER; + esp->e_addr = n; + return; + } + unget(c); + c = '$'; + } + /* + * Evaluate symbols and labels + */ + if (ctype[c] & LETTER) { + esp->e_mode = S_USER; + getid(id, c); + sp = lookup(id); + if (sp->s_type == S_NEW) { + esp->e_addr = 0; + if (sp->s_flag&S_GBL) { + esp->e_flag = 1; + esp->e_base.e_sp = sp; + return; + } + /* err('u'); */ + } else { + esp->e_mode = sp->s_type; + esp->e_addr = sp->s_addr; + esp->e_base.e_ap = sp->s_area; + } + return; + } + /* + * Else not a term. + */ + qerr(); +} + +/*)Function int digit(c, r) + * + * int c digit character + * int r current radix + * + * The function digit() returns the value of c + * in the current radix r. If the c value is not + * a number of the current radix then a -1 is returned. + * + * local variables: + * none + * + * global variables: + * char ctype[] array of character types, one per + * ASCII character + * + * functions called: + * none + * + * side effects: + * none + */ + +int +digit(c, r) +register int c, r; +{ + if (r == 16) { + if (ctype[c] & RAD16) { + if (c >= 'A' && c <= 'F') + return (c - 'A' + 10); + if (c >= 'a' && c <= 'f') + return (c - 'a' + 10); + return (c - '0'); + } + } else + if (r == 10) { + if (ctype[c] & RAD10) + return (c - '0'); + } else + if (r == 8) { + if (ctype[c] & RAD8) + return (c - '0'); + } else + if (r == 2) { + if (ctype[c] & RAD2) + return (c - '0'); + } + return (-1); +} + +/*)Function VOID abscheck(esp) + * + * expr * esp pointer to an expr structure + * + * The function abscheck() tests the evaluation of an + * expression to verify it is absolute. If the evaluation + * is relocatable then an 'r' error is noted and the expression + * made absolute. + * + * Note: The area type (i.e. ABS) is not checked because + * the linker can be told to explicitly relocate an + * absolute area. + * + * local variables: + * none + * + * global variables: + * none + * + * functions called: + * VOID rerr() assubr.c + * + * side effects: + * The expression may be changed to absolute and the + * 'r' error invoked. + */ + +VOID +abscheck(esp) +register struct expr *esp; +{ + if (esp->e_flag || esp->e_base.e_ap) { + esp->e_flag = 0; + esp->e_base.e_ap = NULL; + rerr(); + } +} + +/*)Function int is_abs(esp) + * + * expr * esp pointer to an expr structure + * + * The function is_abs() tests the evaluation of an + * expression to verify it is absolute. If the evaluation + * is absolute then 1 is returned, else 0 is returned. + * + * Note: The area type (i.e. ABS) is not checked because + * the linker can be told to explicitly relocate an + * absolute area. + * + * local variables: + * none + * + * global variables: + * none + * + * functions called: + * none + * + * side effects: + * none + */ + +int +is_abs (esp) +register struct expr *esp; +{ + if (esp->e_flag || esp->e_base.e_ap) { + return(0); + } + return(1); +} + +/*)Function int oprio(c) + * + * int c operator character + * + * The function oprio() returns a relative priority + * for all valid unary and binary operators. + * + * local variables: + * none + * + * global variables: + * none + * + * functions called: + * none + * + * side effects: + * none + */ + +int +oprio(c) +register int c; +{ + if (c == '*' || c == '/' || c == '%') + return (10); + if (c == '+' || c == '-') + return (7); + if (c == '<' || c == '>') + return (5); + if (c == '^') + return (4); + if (c == '&') + return (3); + if (c == '|') + return (1); + return (0); +} + +/*)Function VOID clrexpr(esp) + * + * expr * esp pointer to expression structure + * + * The function clrexpr() clears the expression structure. + * + * local variables: + * none + * + * global variables: + * none + * + * functions called: + * none + * + * side effects: + * expression structure cleared. + */ + +VOID +clrexpr(esp) +register struct expr *esp; +{ + esp->e_mode = 0; + esp->e_flag = 0; + esp->e_addr = 0; + esp->e_base.e_ap = NULL; + esp->e_rlcf = 0; +} diff --git a/as/hc08/aslex.c b/as/hc08/aslex.c new file mode 100644 index 00000000..4f774c42 --- /dev/null +++ b/as/hc08/aslex.c @@ -0,0 +1,520 @@ +/* aslex.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + * + * 28-Oct-97 JLH bug in getst(): sign extend on ~(SPACE|ILL) + * causes infinite loop + */ + +#include +#include +#include +#include "asm.h" + +/*)Module aslex.c + * + * The module aslex.c includes the general lexical + * analysis routines for the assembler. + * + * aslex.c contains the following functions: + * char endline() + * char get() + * VOID getid(id,c) + * int getline() + * int getmap() + * char getnb() + * VOID getst() + * int more() + * VOID unget(c) + * + * aslex.c contains no local/static variables + */ + +/*)Function VOID getid(id,c) + * + * char * id a pointer to a string of + * maximum length NCPS + * int c mode flag + * >=0 this is first character to + * copy to the string buffer + * <0 skip white space, first + * character must be a LETTER + * + * The function getid() scans the current assembler-source text line + * from the current position copying the next LETTER | DIGIT string + * into the external string buffer (id). The string ends when a non + * LETTER or DIGIT character is found. The maximum number of + * characters copied is NCPS. If the input string is larger than + * NCPS characters then the string is truncated, if the input string + * is shorter than NCPS characters then the string is NULL filled. + * If the mode argument (c) is >=0 then (c) is the first character + * copied to the string buffer, if (c) is <0 then intervening white + * space (SPACES and TABS) are skipped and the first character found + * must be a LETTER else a 'q' error terminates the parse of this + * assembler-source text line. + * + * local variables: + * char * p pointer to external string buffer + * int c current character value + * + * global variables: + * char ctype[] a character array which defines the + * type of character being processed. + * This index is the character + * being processed. + * + * called functions: + * char get() aslex.c + * char getnb() aslex.c + * VOID unget() aslex.c + * + * side effects: + * use of getnb(), get(), and unget() updates the + * global pointer ip, the position in the current + * assembler-source text line. + */ + +VOID +getid(id, c) +register int c; +char *id; +{ + register char *p; + + if (c < 0) { + c = getnb(); + if ((ctype[c] & LETTER) == 0) + qerr(); + } + p = id; + do { + if (p < &id[NCPS]) + *p++ = c; + } while (ctype[c=get()] & (LETTER|DIGIT)); + unget(c); + while (p < &id[NCPS]) + *p++ = 0; +} + +/*)Function VOID getst(id,c) + * + * char * id a pointer to a string of + * maximum length NCPS + * int c mode flag + * >=0 this is first character to + * copy to the string buffer + * <0 skip white space, first + * character must be a LETTER + * + * The function getnbid() scans the current assembler-source text line + * from the current position copying the next character string into + * the external string buffer (id). The string ends when a SPACE or + * ILL character is found. The maximum number of + * characters copied is NCPS. If the input string is larger than + * NCPS characters then the string is truncated, if the input string + * is shorter than NCPS characters then the string is NULL filled. + * If the mode argument (c) is >=0 then (c) is the first character + * copied to the string buffer, if (c) is <0 then intervening white + * space (SPACES and TABS) are skipped and the first character found + * must be a LETTER else a 'q' error terminates the parse of this + * assembler-source text line. + * + * local variables: + * char * p pointer to external string buffer + * int c current character value + * + * global variables: + * char ctype[] a character array which defines the + * type of character being processed. + * This index is the character + * being processed. + * + * called functions: + * char get() aslex.c + * char getnb() aslex.c + * VOID unget() aslex.c + * + * side effects: + * use of getnb(), get(), and unget() updates the + * global pointer ip, the position in the current + * assembler-source text line. + */ + +VOID +getst(id, c) +register int c; +char *id; +{ + register char *p; + + if (c < 0) { + c = getnb(); + if ((ctype[c] & LETTER) == 0) + qerr(); + } + p = id; + do { + if (p < &id[NCPS]) + *p++ = c; + } while (ctype[c=get()] & (0xFF - (SPACE|ILL))); + unget(c); + while (p < &id[NCPS]) + *p++ = 0; +} + +/*)Function char getnb() + * + * The function getnb() scans the current assembler-source + * text line returning the first character not a SPACE or TAB. + * + * local variables: + * int c current character from + * assembler-source text line + * + * global variables: + * none + * + * called functions: + * char get() aslex.c + * + * side effects: + * use of get() updates the global pointer ip, the position + * in the current assembler-source text line + */ + +char +getnb() +{ + register int c; + + while ((c=get()) == ' ' || c == '\t') + ; + return (c); +} + +/*)Function char get() + * + * The function get() returns the next character in the + * assembler-source text line, at the end of the line a + * NULL character is returned. + * + * local variables: + * int c current character from + * assembler-source text line + * + * global variables: + * char * ip pointer into the current + * assembler-source text line + * + * called functions: + * none + * + * side effects: + * updates ip to the next character position in the + * assembler-source text line. If ip is at the end of the + * line, ip is not updated. + */ + +char +get() +{ + register int c; + + if ((c = *ip) != 0) + ++ip; + return (c); +} + +/*)Function VOID unget(c) + * + * int c value of last character read from + * assembler-source text line + * + * If (c) is not a NULL character then the global pointer ip + * is updated to point to the preceeding character in the + * assembler-source text line. + * + * NOTE: This function does not push the character (c) + * back into the assembler-source text line, only + * the pointer ip is changed. + * + * local variables: + * int c last character read from + * assembler-source text line + * + * global variables: + * char * ip position into the current + * assembler-source text line + * + * called functions: + * none + * + * side effects: + * ip decremented by 1 character position + */ + +VOID +unget(c) +{ + if (c) + if (ip != ib) + --ip; +} + +/*)Function int getmap(d) + * + * int d value to compare with the + * assembler-source text line character + * + * The function getmap() converts the 'C' style characters \b, \f, + * \n, \r, and \t to their equivalent ascii values and also + * converts 'C' style octal constants '\123' to their equivalent + * numeric values. If the first character is equivalent to (d) then + * a (-1) is returned, if the end of the line is detected then + * a 'q' error terminates the parse for this line, or if the first + * character is not a \ then the character value is returned. + * + * local variables: + * int c value of character from the + * assembler-source text line + * int n looping counter + * int v current value of numeric conversion + * + * global variables: + * none + * + * called functions: + * char get() aslex.c + * + * side effects: + * use of get() updates the global pointer ip the position + * in the current assembler-source text line + */ + +int +getmap(d) +{ + register int c, n, v; + + if ((c=get()) == '\0') + qerr(); + if (c == d) + return (-1); + if (c == '\\') { + c = get(); + switch (c) { + + case 'b': + c = '\b'; + break; + + case 'f': + c = '\f'; + break; + + case 'n': + c = '\n'; + break; + + case 'r': + c = '\r'; + break; + + case 't': + c = '\t'; + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + n = 0; + v = 0; + while (++n<=3 && c>='0' && c<='7') { + v = (v<<3) + c - '0'; + c = get(); + } + unget(c); + c = v; + break; + } + } + return (c); +} + +/*)Function int getline() + * + * The function getline() reads a line of assembler-source text + * from an assembly source text file or an include file. + * Lines of text are processed from assembler-source files until + * all files have been read. If an include file is opened then + * lines of text are read from the include file (or nested + * include file) until the end of the include file is found. + * The input text line is copied into the global string ib[] + * and converted to a NULL terminated string. The function + * getline() returns a (1) after succesfully reading a line + * or a (0) if all files have been read. + * + * local variables: + * int i string length + * + * global variables: + * char ib[] string buffer containing + * assembler-source text line + * char ifp[] array of file handles for + * include files + * int incfil index for ifp[] specifies + * active include file + * int incline[] array of include file + * line numbers + * char sfp[] array of file handles for + * assembler source files + * int cfile index for sfp[] specifies + * active source file + * int srcline[] array of source file + * line numbers + * int inpfil maximum input file index + * + * called functions: + * int fclose() c-library + * char * fgets() c-library + * int strlen() c-library + * + * side effects: + * include file will be closed at detection of end of file. + * the next sequential source file may be selected. + * the global file indexes incfil or cfile may be changed. + * The respective source line or include line counter + * will be updated. + */ + +int +getline() +{ +loop: if (incfil >= 0) { + if (fgets(ib, sizeof ib, ifp[incfil]) == NULL) { + fclose(ifp[incfil--]); + lop = NLPP; + goto loop; + } else { + ++incline[incfil]; + } + } else { + if (fgets(ib, sizeof ib, sfp[cfile]) == NULL) { + if (++cfile <= inpfil) { + srcline[cfile] = 0; + goto loop; + } + return (0); + } else { + ++srcline[cfile]; + } + } + chop_crlf(ib); + return (1); +} + +/*)Function int more() + * + * The function more() scans the assembler-source text line + * skipping white space (SPACES and TABS) and returns a (0) + * if the end of the line or a comment delimeter (;) is found, + * or a (1) if their are additional characters in the line. + * + * local variables: + * int c next character from the + * assembler-source text line + * + * global variables: + * none + * + * called functions: + * char getnb() aslex.c + * VOID unget() aslex.c + * + * side effects: + * use of getnb() and unget() updates the global pointer ip + * the position in the current assembler-source text line + */ + +int +more() +{ + register int c; + + c = getnb(); + unget(c); + return( (c == '\0' || c == ';') ? 0 : 1 ); +} + +/*)Function char endline() + * + * The function endline() scans the assembler-source text line + * skipping white space (SPACES and TABS) and returns the next + * character or a (0) if the end of the line is found or a + * comment delimiter (;) is found. + * + * local variables: + * int c next character from the + * assembler-source text line + * + * global variables: + * none + * + * called functions: + * char getnb() aslex.c + * + * side effects: + * use of getnb() updates the global pointer ip the + * position in the current assembler-source text line + */ + +char +endline() +{ + register int c; + + c = getnb(); + return( (c == '\0' || c == ';') ? 0 : c ); +} + +/*)Function VOID chop_crlf(str) + * + * char *str string to chop + * + * The function chop_crlf() removes trailing LF or CR/LF from + * str, if present. + * + * local variables: + * int i string length + * + * global variables: + * none + * + * functions called: + * none + * + * side effects: + * none + */ + +VOID +chop_crlf(str) +char *str; +{ + register int i; + + i = strlen(str); + if (i >= 1 && str[i-1] == '\n') str[i-1] = 0; + if (i >= 2 && str[i-2] == '\r') str[i-2] = 0; +} diff --git a/as/hc08/aslink.h b/as/hc08/aslink.h new file mode 100644 index 00000000..263467a0 --- /dev/null +++ b/as/hc08/aslink.h @@ -0,0 +1,775 @@ +/* aslink.h */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + * + * 28-Oct-97 JLH: + * - add proto for StoreString + * - change s_id from [NCPS] to pointer + * - change NCPS to 80 + * - case sensitive + * - add R_J11 for 8051 assembler + * 31-Oct-97 JLH: + * - add jflag and jfp for NoICE output + * 30-Jan-98 JLH: + * - add memory space flags to a_flag for 8051 + */ + +#define VERSION "V01.70 + NoICE + SDCC Feb 1999" + +/* + * Case Sensitivity Flag + */ +#define CASE_SENSITIVE 1 + +/*)Module asmlnk.h + * + * The module asmlnk.h contains the definitions for constants, + * structures, global variables, and LKxxxx functions + * contained in the LKxxxx.c files. + */ + +/*)BUILD + $(PROGRAM) = ASLINK + $(INCLUDE) = ASLINK.H + $(FILES) = { + LKMAIN.C + LKLEX.C + LKAREA.C + LKHEAD.C + LKSYM.C + LKEVAL.C + LKDATA.C + LKLIST.C + LKRLOC.C + LKLIBR.C + LKS19.C + LKIHX.C + } + $(STACK) = 2000 +*/ + +/* DECUS C void definition */ +/* File/extension seperator */ + +#ifdef decus +#define VOID char +#define FSEPX '.' +#endif + +/* PDOS C void definition */ +/* File/extension seperator */ + +#ifdef PDOS +#define VOID char +#define FSEPX ':' +#endif + +/* Default void definition */ +/* File/extension seperator */ + +#ifndef VOID +#define VOID void +#define FSEPX '.' +#define OTHERSYSTEM +#endif + +/* + * PATH_MAX + */ +#include +#ifndef PATH_MAX /* POSIX, but not required */ + #if defined(__BORLANDC__) || defined(_MSC_VER) + #include + #define PATH_MAX _MAX_PATH + #else + #define PATH_MAX 255 /* define a reasonable value */ + #endif +#endif + +/* + * This file defines the format of the + * relocatable binary file. + */ + +#define NCPS 80 /* characters per symbol (JLH: change from 8) */ +#define NDATA 16 /* actual data */ +#define NINPUT PATH_MAX /* Input buffer size */ +#define NHASH 64 /* Buckets in hash table */ +#define HMASK 077 /* Hash mask */ +#define NLPP 60 /* Lines per page */ +#define NTXT 16 /* T values */ + +/* + * The "R_" relocation constants define values used in + * generating the assembler relocation output data for + * areas, symbols, and code. + * + * + * Relocation types. + * + * 7 6 5 4 3 2 1 0 + * +-----+-----+-----+-----+-----+-----+-----+-----+ + * | MSB | PAGn| PAG0| USGN| BYT2| PCR | SYM | BYT | + * +-----+-----+-----+-----+-----+-----+-----+-----+ + */ + +#define R_WORD 0x00 /* 16 bit */ +#define R_BYTE 0x01 /* 8 bit */ + +#define R_AREA 0x00 /* Base type */ +#define R_SYM 0x02 + +#define R_NORM 0x00 /* PC adjust */ +#define R_PCR 0x04 + +#define R_BYT1 0x00 /* Byte count for R_BYTE = 1 */ +#define R_BYT2 0x08 /* Byte count for R_BYTE = 2 */ + +#define R_SGND 0x00 /* Signed Byte */ +#define R_USGN 0x10 /* Unsigned Byte */ + +#define R_NOPAG 0x00 /* Page Mode */ +#define R_PAG0 0x20 /* Page '0' */ +#define R_PAG 0x40 /* Page 'nnn' */ + +#define R_LSB 0x00 /* low byte */ +#define R_MSB 0x80 /* high byte */ + +#define R_BYT3 0x100 /* if R_BYTE is set, this is a + * 3 byte address, of which + * the linker must select one byte. + */ +#define R_HIB 0x200 /* If R_BYTE & R_BYT3 are set, linker + * will select byte 3 of the relocated + * 24 bit address. + */ + +#define R_J11 (R_WORD|R_BYT2) /* JLH: 11 bit JMP and CALL (8051) */ +#define R_J19 (R_WORD|R_BYT2|R_MSB) /* 19 bit JMP/CALL (DS80C390) */ +#define R_C24 (R_WORD|R_BYT1|R_MSB) /* 24 bit address (DS80C390) */ +#define R_J19_MASK (R_BYTE|R_BYT2|R_MSB) + +#define IS_R_J19(x) (((x) & R_J19_MASK) == R_J19) +#define IS_R_J11(x) (((x) & R_J19_MASK) == R_J11) +#define IS_C24(x) (((x) & R_J19_MASK) == R_C24) + +#define R_ESCAPE_MASK 0xf0 /* Used to escape relocation modes + * greater than 0xff in the .rel + * file. + */ + +/* + * Global symbol types. + */ +#define S_REF 1 /* referenced */ +#define S_DEF 2 /* defined */ + +/* + * Area type flags + */ +#define A_CON 0000 /* concatenate */ +#define A_OVR 0004 /* overlay */ +#define A_REL 0000 /* relocatable */ +#define A_ABS 0010 /* absolute */ +#define A_NOPAG 0000 /* non-paged */ +#define A_PAG 0020 /* paged */ + +/* Additional flags for 8051 address spaces */ +#define A_DATA 0000 /* data space (default)*/ +#define A_CODE 0040 /* code space */ +#define A_XDATA 0100 /* external data space */ +#define A_BIT 0200 /* bit addressable space */ + +/* + * File types + */ +#define F_STD 1 /* stdin */ +#define F_LNK 2 /* File.lnk */ +#define F_REL 3 /* File.rel */ + +/* + * General assembler address type + */ +typedef unsigned int Addr_T; + +/* + * The structures of head, area, areax, and sym are created + * as the REL files are read during the first pass of the + * linker. The struct head is created upon encountering a + * H directive in the REL file. The structure contains a + * link to a link file structure (struct lfile) which describes + * the file containing the H directive, the number of data/code + * areas contained in this header segment, the number of + * symbols referenced/defined in this header segment, a pointer + * to an array of pointers to areax structures (struct areax) + * created as each A directive is read, and a pointer to an + * array of pointers to symbol structures (struct sym) for + * all referenced/defined symbols. As H directives are read + * from the REL files a linked list of head structures is + * created by placing a link to the new head structure + * in the previous head structure. + */ +struct head +{ + struct head *h_hp; /* Header link */ + struct lfile *h_lfile;/* Associated file */ + int h_narea; /* # of areas */ + struct areax **a_list; /* Area list */ + int h_nglob; /* # of global symbols */ + struct sym **s_list; /* Globle symbol list */ + char m_id[NCPS]; /* Module name */ +}; + +/* + * A structure area is created for each 'unique' data/code + * area definition found as the REL files are read. The + * struct area contains the name of the area, a flag byte + * which contains the area attributes (REL/CON/OVR/ABS), + * an area subtype (not used in this assembler), and the + * area base address and total size which will be filled + * in at the end of the first pass through the REL files. + * As A directives are read from the REL files a linked + * list of unique area structures is created by placing a + * link to the new area structure in the previous area structure. + */ +struct area +{ + struct area *a_ap; /* Area link */ + struct areax *a_axp; /* Area extension link */ + Addr_T a_addr; /* Beginning address of area */ + Addr_T a_size; /* Total size of the area */ + char a_type; /* Area subtype */ + char a_flag; /* Flag byte */ + char a_id[NCPS]; /* Name */ +}; + +/* + * An areax structure is created for every A directive found + * while reading the REL files. The struct areax contains a + * link to the 'unique' area structure referenced by the A + * directive and to the head structure this area segment is + * a part of. The size of this area segment as read from the + * A directive is placed in the areax structure. The beginning + * address of this segment will be filled in at the end of the + * first pass through the REL files. As A directives are read + * from the REL files a linked list of areax structures is + * created for each unique area. The final areax linked + * list has at its head the 'unique' area structure linked + * to the linked areax structures (one areax structure for + * each A directive for this area). + */ +struct areax +{ + struct areax *a_axp; /* Area extension link */ + struct area *a_bap; /* Base area link */ + struct head *a_bhp; /* Base header link */ + Addr_T a_addr; /* Beginning address of section */ + Addr_T a_size; /* Size of the area in section */ +}; + +/* + * A sym structure is created for every unique symbol + * referenced/defined while reading the REL files. The + * struct sym contains the symbol's name, a flag value + * (not used in this linker), a symbol type denoting + * referenced/defined, and an address which is loaded + * with the relative address within the area in which + * the symbol was defined. The sym structure also + * contains a link to the area where the symbol was defined. + * The sym structures are linked into linked lists using + * the symbol link element. + */ +struct sym +{ + struct sym *s_sp; /* Symbol link */ + struct areax *s_axp; /* Symbol area link */ + char s_type; /* Symbol subtype */ + char s_flag; /* Flag byte */ + Addr_T s_addr; /* Address */ + char *s_id; /* Name: JLH change from [NCPS] */ +}; + +/* + * The structure lfile contains a pointer to a + * file specification string, the file type, and + * a link to the next lfile structure. + */ +struct lfile +{ + struct lfile *f_flp; /* lfile link */ + int f_type; /* File type */ + char *f_idp; /* Pointer to file spec */ +}; + +/* + * The struct base contains a pointer to a + * base definition string and a link to the next + * base structure. + */ +struct base +{ + struct base *b_base; /* Base link */ + char *b_strp; /* String pointer */ +}; + +/* + * The struct globl contains a pointer to a + * global definition string and a link to the next + * global structure. + */ +struct globl +{ + struct globl *g_globl; /* Global link */ + char *g_strp; /* String pointer */ +}; + +/* + * A structure sdp is created for each 'unique' paged + * area definition found as the REL files are read. + * As P directives are read from the REL files a linked + * list of unique sdp structures is created by placing a + * link to the new sdp structure in the previous area structure. + */ +struct sdp +{ + struct area *s_area; /* Paged Area link */ + struct areax *s_areax; /* Paged Area Extension Link */ + Addr_T s_addr; /* Page address offset */ +}; + +/* + * The structure rerr is loaded with the information + * required to report an error during the linking + * process. The structure contains an index value + * which selects the areax structure from the header + * areax structure list, a mode value which selects + * symbol or area relocation, the base address in the + * area section, an area/symbol list index value, and + * an area/symbol offset value. + */ +struct rerr +{ + int aindex; /* Linking area */ + int mode; /* Relocation mode */ + Addr_T rtbase; /* Base address in section */ + int rindex; /* Area/Symbol reloaction index */ + Addr_T rval; /* Area/Symbol offset value */ +}; + +/* + * The structure lbpath is created for each library + * path specification input by the -k option. The + * lbpath structures are linked into a list using + * the next link element. + */ +struct lbpath { + struct lbpath *next; + char *path; +}; + +/* + * The structure lbname is created for all combinations of the + * library path specifications (input by the -k option) and the + * library file specifications (input by the -l option) that + * lead to an existing file. The element path points to + * the path string, element libfil points to the library + * file string, and the element libspc is the concatenation + * of the valid path and libfil strings. + * + * The lbpath structures are linked into a list + * using the next link element. + * + * Each library file contains a list of object files + * that are contained in the particular library. e.g.: + * + * \iolib\termio + * \inilib\termio + * + * Only one specification per line is allowed. + */ +struct lbname { + struct lbname *next; + char *path; + char *libfil; + char *libspc; +}; + +/* + * The function fndsym() searches through all combinations of the + * library path specifications (input by the -k option) and the + * library file specifications (input by the -l option) that + * lead to an existing file for a symbol definition. + * + * The structure lbfile is created for the first library + * object file which contains the definition for the + * specified undefined symbol. + * + * The element libspc points to the library file path specification + * and element relfil points to the object file specification string. + * The element filspc is the complete path/file specification for + * the library file to be imported into the linker. The + * file specicifation may be formed in one of two ways: + * + * (1) If the library file contained an absolute + * path/file specification then this becomes filspc. + * (i.e. C:\...) + * + * (2) If the library file contains a relative path/file + * specification then the concatenation of the path + * and this file specification becomes filspc. + * (i.e. \...) + * + * The lbpath structures are linked into a list + * using the next link element. + */ +struct lbfile { + struct lbfile *next; + char *libspc; + char *relfil; + char *filspc; + long offset; /*>=0 if rel file is embedded in a lib file at this offset*/ +}; + +/* + * External Definitions for all Global Variables + */ + +extern char *_abs_; /* = { ". .ABS." }; + */ +extern int lkerr; /* ASLink error flag + */ +extern char *ip; /* pointer into the REL file + * text line in ib[] + */ +extern char ib[NINPUT]; /* REL file text line + */ +extern char *rp; /* pointer into the LST file + * text line in rb[] + */ +extern char rb[NINPUT]; /* LST file text line being + * address relocated + */ +extern unsigned char ctype[]; /* array of character types, one per + * ASCII character + */ + +extern char sdccopt[NINPUT]; +extern char sdccopt_module[NINPUT]; +extern char curr_module[NINPUT]; + +/* + * Character Type Definitions + */ +#define SPACE 0000 +#define ETC 0000 +#define LETTER 0001 +#define DIGIT 0002 +#define BINOP 0004 +#define RAD2 0010 +#define RAD8 0020 +#define RAD10 0040 +#define RAD16 0100 +#define ILL 0200 + +#define DGT2 DIGIT|RAD16|RAD10|RAD8|RAD2 +#define DGT8 DIGIT|RAD16|RAD10|RAD8 +#define DGT10 DIGIT|RAD16|RAD10 +#define LTR16 LETTER|RAD16 + +#if CASE_SENSITIVE +#else +extern char ccase[]; /* an array of characters which + * perform the case translation function + */ +#endif + +extern struct lfile *filep; /* The pointers (lfile *) filep, + * (lfile *) cfp, and (FILE *) sfp + * are used in conjunction with + * the routine getline() to read + * asmlnk commands from + * (1) the standard input or + * (2) or a command file + * and to read the REL files + * sequentially as defined by the + * asmlnk input commands. + * + * The pointer *filep points to the + * beginning of a linked list of + * lfile structures. + */ +extern struct lfile *cfp; /* The pointer *cfp points to the + * current lfile structure + */ +extern struct lfile *startp;/* asmlnk startup file structure + */ +extern struct lfile *linkp; /* pointer to first lfile structure + * containing an input REL file + * specification + */ +extern struct lfile *lfp; /* pointer to current lfile structure + * being processed by parse() + */ +extern struct head *headp; /* The pointer to the first + * head structure of a linked list + */ +extern struct head *hp; /* Pointer to the current + * head structure + */ +extern struct area *areap; /* The pointer to the first + * area structure of a linked list + */ +extern struct area *ap; /* Pointer to the current + * area structure + */ +extern struct areax *axp; /* Pointer to the current + * areax structure + */ +extern struct sym *symhash[NHASH]; /* array of pointers to NHASH + * linked symbol lists + */ +extern struct base *basep; /* The pointer to the first + * base structure + */ +extern struct base *bsp; /* Pointer to the current + * base structure + */ +extern struct globl *globlp;/* The pointer to the first + * globl structure + */ +extern struct globl *gsp; /* Pointer to the current + * globl structure + */ +extern struct sdp sdp; /* Base Paged structure + */ +extern struct rerr rerr; /* Structure containing the + * linker error information + */ +extern FILE *ofp; /* Linker Output file handle + */ +extern FILE *mfp; /* Map output file handle + */ +extern FILE *jfp; /* NoICE output file handle + */ +extern FILE *rfp; /* File handle for output + * address relocated ASxxxx + * listing file + */ +extern FILE *sfp; /* The file handle sfp points to the + * currently open file + */ +extern FILE *tfp; /* File handle for input + * ASxxxx listing file + */ +extern FILE *dfp; /* File handle for debug info output + */ +extern int dflag; /* Output debug information flag + */ +extern int oflag; /* Output file type flag + */ +extern int mflag; /* Map output flag + */ +extern int sflag; /* JCF: Memory usage output flag + */ +extern int jflag; /* NoICE output flag + */ +extern int xflag; /* Map file radix type flag + */ +extern int pflag; /* print linker command file flag + */ +extern int uflag; /* Listing relocation flag + */ +extern int rflag; /* Extended linear address record flag. + */ +extern int radix; /* current number conversion radix: + * 2 (binary), 8 (octal), 10 (decimal), + * 16 (hexadecimal) + */ +extern int line; /* current line number + */ +extern int page; /* current page number + */ +extern int lop; /* current line number on page + */ +extern int pass; /* linker pass number + */ +extern int rtcnt; /* count of elements in the + * rtval[] and rtflg[] arrays + */ +extern Addr_T rtval[]; /* data associated with relocation + */ +extern int rtflg[]; /* indicates if rtval[] value is + * to be sent to the output file. + * (always set in this linker) + */ +extern int hilo; /* REL file byte ordering + */ +extern int gline; /* LST file relocation active + * for current line + */ +extern int gcntr; /* LST file relocation active + * counter + */ +extern struct lbpath *lbphead; /* pointer to the first + * library path structure + */ +extern struct lbname *lbnhead; /* pointer to the first + * library name structure + */ +extern struct lbfile *lbfhead; /* pointer to the first + * library file structure + */ +extern Addr_T iram_size; /* internal ram size + */ +extern long xram_size; /* external ram size + */ +extern long code_size; /* code size + */ + + +/* C Library function definitions */ +/* for reference only +extern VOID exit(); +extern int fclose(); +extern char * fgets(); +extern FILE * fopen(); +extern int fprintf(); +extern VOID free(); +extern VOID * malloc(); +extern char putc(); +extern char * strcpy(); +extern int strlen(); +extern char * strncpy(); +*/ + +/* Program function definitions */ + +/* lkmain.c */ +extern FILE * afile(); +extern VOID bassav(); +extern VOID gblsav(); +extern VOID iramsav(); +extern VOID xramsav(); +extern VOID codesav(); +extern VOID iramcheck(); +extern VOID link_main(); +extern VOID lkexit(); +extern int main(); +extern VOID map(); +extern int parse(); +extern VOID setbas(); +extern VOID setgbl(); +extern VOID usage(); +extern VOID copyfile(); + +/* lklex.c */ +extern char endline(); +extern char get(); +extern VOID getfid(); +extern VOID getid(); +extern VOID getSid(); +extern int getline(); +extern int getmap(); +extern char getnb(); +extern int more(); +extern VOID skip(); +extern VOID unget(); +extern VOID chop_crlf(); + +/* lkarea.c */ +extern VOID lkparea(); +extern VOID lnkarea(); +extern VOID lnksect(); +extern VOID newarea(); + +/* lkhead.c */ +extern VOID module(); +extern VOID newhead(); + +/* lksym.c */ +extern int hash(); +extern struct sym * lkpsym(); +extern VOID * new(); +extern struct sym * newsym(); +extern VOID symdef(); +extern int symeq(); +extern VOID syminit(); +extern VOID symmod(); +extern Addr_T symval(); + +/* lkeval.c */ +extern int digit(); +extern Addr_T eval(); +extern Addr_T expr(); +extern int oprio(); +extern Addr_T term(); + +/* lklist.c */ +extern int dgt(); +extern VOID lkulist(); +extern VOID lkalist(); +extern VOID lkglist(); +extern VOID lstarea(); +extern VOID newpag(); +extern VOID slew(); + +/* lkrloc.c */ +extern Addr_T adb_b(); +extern Addr_T adb_hi(); +extern Addr_T adb_lo(); +extern Addr_T adb_24_hi(Addr_T v, int i); +extern Addr_T adb_24_mid(Addr_T v, int i); +extern Addr_T adb_24_lo(Addr_T v, int i); +extern Addr_T adw_w(); +extern Addr_T adw_24(Addr_T, int); +extern Addr_T adw_hi(); +extern Addr_T adw_lo(); +extern Addr_T evword(); +extern VOID rele(); +extern VOID reloc(); +extern VOID relt(); +extern VOID relr(); +extern VOID relp(); +extern VOID relerr(); +extern char * errmsg[]; +extern VOID errdmp(); +extern VOID relerp(); +extern VOID erpdmp(); +extern VOID prntval(); +extern int lastExtendedAddress; + +/* lklibr.c */ +extern int addfile(); +extern VOID addlib(); +extern VOID addpath(); +extern int fndsym(); +extern VOID library(); +extern VOID loadfile(); +extern VOID search(); + +/* lks19.c */ +extern VOID s19(); + +/* lkihx.c */ +extern VOID ihx(); +extern VOID ihxEntendedLinearAddress(Addr_T); +extern VOID newArea(); + +/* lkstore.c */ +extern char *StoreString( char *str ); + +/* lknoice.c */ +extern void DefineNoICE( char *name, Addr_T value, int page ); + +/* JCF: lkmem.c */ +extern int summary(struct area * xp); + +/* JCF: lkaomf51.c */ +extern void SaveLinkedFilePath(char * filepath); +extern void CreateAOMF51(void); diff --git a/as/hc08/aslink.mak b/as/hc08/aslink.mak new file mode 100644 index 00000000..300803d9 --- /dev/null +++ b/as/hc08/aslink.mak @@ -0,0 +1,263 @@ +ORIGIN = Symantec C++ +ORIGIN_VER = Version 7.00 +VERSION = RELEASE + +!IFDEF SUB_DEBUG +DEBUG = $(SUB_DEBUG) +NDEBUG = !$(SUB_DEBUG) +!ELSE +DEBUG = 0 +NDEBUG = 1 +!ENDIF + +PROJ = ASLINK +APPTYPE = DOS EXE +PROJTYPE = EXE + +CC = SC +CPP = SPP +MAKE = SMAKE +RC = RCC +HC = HC31 +ASM = SC +DISASM = OBJ2ASM +LNK = LINK +DLLS = + +HEADERS = ..\linksrc\aslink.h + +DEFFILE = ASLINK.DEF + +!IF $(DEBUG) +OUTPUTDIR = . +CREATEOUTPUTDIR = +TARGETDIR = . +CREATETARGETDIR = + +LIBS = + +CFLAGS = -A -Jm -J -ms -o+time -S -2 -a2 -c +LFLAGS = /PACKF +DEFINES = -D_DEBUG=1 +!ELSE +OUTPUTDIR = . +CREATEOUTPUTDIR = +TARGETDIR = . +CREATETARGETDIR = + +LIBS = + +CFLAGS = -A -Jm -J -ms -o+time -S -2 -a2 -c +LFLAGS = /PACKF +DEFINES = +!ENDIF + +HFLAGS = $(CFLAGS) +MFLAGS = MASTERPROJ=$(PROJ) +LIBFLAGS = /C +RESFLAGS = +DEBUGGERFLAGS = -LOADSYMBOLS +AFLAGS = $(CFLAGS) +HELPFLAGS = + +MODEL = S + +PAR = PROJS BATS OBJS + +RCDEFINES = + +LIBDIRS = + +INCLUDES = -Ic:\asxxxx\linksrc + +INCLUDEDOBJS = + +OBJS = $(OUTPUTDIR)\lkarea.OBJ $(OUTPUTDIR)\lkdata.OBJ $(OUTPUTDIR)\lkeval.OBJ \ + $(OUTPUTDIR)\lkhead.OBJ $(OUTPUTDIR)\lkihx.OBJ $(OUTPUTDIR)\lklex.OBJ $(OUTPUTDIR)\lklibr.OBJ \ + $(OUTPUTDIR)\lklist.OBJ $(OUTPUTDIR)\lkmain.OBJ $(OUTPUTDIR)\lkrloc.OBJ $(OUTPUTDIR)\lks19.OBJ \ + $(OUTPUTDIR)\lksym.OBJ + +RCFILES = + +RESFILES = + +SYMS = + +HELPFILES = + +BATS = + +.SUFFIXES: .C .CP .CPP .CXX .CC .H .HPP .HXX .COM .EXE .DLL .LIB .RTF .DLG .ASM .RES .RC .OBJ + +.C.OBJ: + $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o$*.obj $*.c + +.CPP.OBJ: + $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o$*.obj $*.cpp + +.CXX.OBJ: + $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o$*.obj $*.cxx + +.CC.OBJ: + $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o$*.obj $*.cc + +.CP.OBJ: + $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o$*.obj $*.cp + +.H.SYM: + $(CC) $(HFLAGS) $(DEFINES) $(INCLUDES) -HF -o$(*B).sym $*.h + +.HPP.SYM: + $(CC) $(HFLAGS) $(DEFINES) $(INCLUDES) -HF -o$(*B).sym $*.hpp + +.HXX.SYM: + $(CC) $(HFLAGS) $(DEFINES) $(INCLUDES) -HF -o$(*B).sym $*.hxx + +.C.EXP: + $(CPP) $(CFLAGS) $(DEFINES) $(INCLUDES) $*.c -o$*.lst + +.CPP.EXP: + $(CPP) $(CFLAGS) $(DEFINES) $(INCLUDES) $*.cpp -o$*.lst + +.CXX.EXP: + $(CPP) $(CFLAGS) $(DEFINES) $(INCLUDES) $*.cxx -o$*.lst + +.CP.EXP: + $(CPP) $(CFLAGS) $(DEFINES) $(INCLUDES) $*.cp -o$*.lst + +.CC.EXP: + $(CPP) $(CFLAGS) $(DEFINES) $(INCLUDES) $*.cc -o$*.lst + +.ASM.EXP: + $(CPP) $(CFLAGS) $(DEFINES) $(INCLUDES) $*.asm -o$*.lst + +.OBJ.COD: + $(DISASM) $*.OBJ >$*.cod + +.OBJ.EXE: + $(LNK) $(LFLAGS) @$(PROJ).LNK + +.RTF.HLP: + $(HC) $(HELPFLAGS) $*.HPJ + +.ASM.OBJ: + $(ASM) $(AFLAGS) $(DEFINES) $(INCLUDES) -o$*.obj $*.asm + +.RC.RES: + $(RC) $(RCDEFINES) $(RESFLAGS) $(INCLUDES) $*.rc -o$*.res + +.DLG.RES: + echo ^#include "windows.h" >$$$*.rc + echo ^IF EXIST "$*.h" >>$$$*.rc + echo ^#include "$*.h" >>$$$*.rc + echo ^#include "$*.dlg" >>$$$*.rc + $(RC) $(RCDEFINES) $(RESFLAGS) $(INCLUDES) $$$*.rc + -del $*.res + -ren $$$*.res $*.res + + + +all: createdir $(PRECOMPILE) $(SYMS) $(OBJS) $(INCLUDEDOBJS) $(POSTCOMPILE) $(TARGETDIR)\$(PROJ).$(PROJTYPE) $(POSTLINK) _done + +createdir: + $(CREATEOUTPUTDIR) + $(CREATETARGETDIR) + +$(TARGETDIR)\$(PROJ).$(PROJTYPE): $(OBJS) $(INCLUDEDOBJS) $(RCFILES) $(RESFILES) $(HELPFILES) + $(LNK) $(LFLAGS) @$(PROJ).LNK; + -del $(TARGETDIR)\$(PROJ).$(PROJTYPE) + -ren $(TARGETDIR)\$$SCW$$.$(PROJTYPE) $(PROJ).$(PROJTYPE) + -echo $(TARGETDIR)\$(PROJ).$(PROJTYPE) built + +_done: + -echo $(PROJ).$(PROJTYPE) done + +buildall: clean all + + +clean: + -del $(TARGETDIR)\$$SCW$$.$(PROJTYPE) + -del $(TARGETDIR)\$(PROJ).CLE + -del $(OUTPUTDIR)\SCPH.SYM + -del $(OBJS) + +cleanres: + +res: cleanres $(RCFILES) all + + +link: + $(LNK) $(LFLAGS) @$(PROJ).LNK; + -del $(TARGETDIR)\$(PROJ).$(PROJTYPE) + -ren $(TARGETDIR)\$$SCW$$.$(PROJTYPE) $(PROJ).$(PROJTYPE) + + + + +!IF EXIST (ASLINK.dpd) +!INCLUDE ASLINK.dpd +!ENDIF + + + +$(OUTPUTDIR)\lkarea.OBJ: ..\linksrc\lkarea.c + $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o$(OUTPUTDIR)\lkarea.obj ..\linksrc\lkarea.c + + + +$(OUTPUTDIR)\lkdata.OBJ: ..\linksrc\lkdata.c + $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o$(OUTPUTDIR)\lkdata.obj ..\linksrc\lkdata.c + + + +$(OUTPUTDIR)\lkeval.OBJ: ..\linksrc\lkeval.c + $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o$(OUTPUTDIR)\lkeval.obj ..\linksrc\lkeval.c + + + +$(OUTPUTDIR)\lkhead.OBJ: ..\linksrc\lkhead.c + $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o$(OUTPUTDIR)\lkhead.obj ..\linksrc\lkhead.c + + + +$(OUTPUTDIR)\lkihx.OBJ: ..\linksrc\lkihx.c + $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o$(OUTPUTDIR)\lkihx.obj ..\linksrc\lkihx.c + + + +$(OUTPUTDIR)\lklex.OBJ: ..\linksrc\lklex.c + $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o$(OUTPUTDIR)\lklex.obj ..\linksrc\lklex.c + + + +$(OUTPUTDIR)\lklibr.OBJ: ..\linksrc\lklibr.c + $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o$(OUTPUTDIR)\lklibr.obj ..\linksrc\lklibr.c + + + +$(OUTPUTDIR)\lklist.OBJ: ..\linksrc\lklist.c + $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o$(OUTPUTDIR)\lklist.obj ..\linksrc\lklist.c + + + +$(OUTPUTDIR)\lkmain.OBJ: ..\linksrc\lkmain.c + $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o$(OUTPUTDIR)\lkmain.obj ..\linksrc\lkmain.c + + + +$(OUTPUTDIR)\lkrloc.OBJ: ..\linksrc\lkrloc.c + $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o$(OUTPUTDIR)\lkrloc.obj ..\linksrc\lkrloc.c + + + +$(OUTPUTDIR)\lks19.OBJ: ..\linksrc\lks19.c + $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o$(OUTPUTDIR)\lks19.obj ..\linksrc\lks19.c + + + +$(OUTPUTDIR)\lksym.OBJ: ..\linksrc\lksym.c + $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o$(OUTPUTDIR)\lksym.obj ..\linksrc\lksym.c + + + + diff --git a/as/hc08/aslist.c b/as/hc08/aslist.c new file mode 100644 index 00000000..2224403a --- /dev/null +++ b/as/hc08/aslist.c @@ -0,0 +1,739 @@ +/* aslist.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + * + * 28-Oct-97 JLH: + * - lstsym: show s_id as string rather than array [NCPS] + */ + +#include +#include +#include +#include +#include "asm.h" + +/*)Module aslist.c + * + * The module aslist.c contains all the functions used + * to generate the assembler list and symbol output files. + * + * aslist.c contains the following functions: + * VOID list() + * VOID list1() + * VOID list2() + * VOID slew() + * VOID lstsym() + * + * The module aslist.c contains no local/static variables + */ + +/*)Function VOID list() + * + * The function list() generates the listing output + * which includes the input source, line numbers, + * and generated code. Numerical output may be selected + * as hexadecimal, decimal, or octal. + * + * local variables: + * int * wp pointer to the assembled data bytes + * int * wpt pointer to the data byte mode + * int nb computed number of assembled bytes + * + * global variables: + * int cb[] array of assembler output values + * int cbt[] array of assembler relocation types + * describing the data in cb[] + * int * cp pointer to assembler output array cb[] + * int * cpt pointer to assembler relocation type + * output array cbt[] + * char eb[] array of generated error codes + * char * ep pointer into error list + * array eb[] + * char ib[] assembler-source text line + * FILE * lfp list output file handle + * int line current assembler source line number + * int lmode listing mode + * int xflag -x, listing radix flag + * + * functions called: + * int fprintf() c_library + * VOID list1() aslist.c + * int putc() c_library + * VOID slew() asslist.c + * + * side effects: + * Listing or symbol output updated. + */ + +VOID +list() +{ + register char *wp; + register int *wpt; + register int nb; + + if (lfp == NULL || lmode == NLIST) + return; + + /* + * Get Correct Line Number + */ + if (incfil >= 0) { + line = incline[incfil]; + if (line == 0) { + if (incfil > 0) { + line = incline[incfil-1]; + } else { + line = srcline[cfile]; + } + } + } else { + line = srcline[cfile]; + } + + /* + * Move to next line. + */ + slew(lfp, pflag); + + /* + * Output a maximum of NERR error codes with listing. + */ + while (ep < &eb[NERR]) + *ep++ = ' '; + fprintf(lfp, "%.2s", eb); + + /* + * Source listing only option. + */ + if (lmode == SLIST) { + fprintf(lfp, "%24s%5u %s\n", "", line, ib); + return; + } + if (lmode == ALIST) { + outchk(HUGE,HUGE); + } + + /* + * HEX output Option. + */ + if (xflag == 0) { /* HEX */ + /* + * Equate only + */ + if (lmode == ELIST) { + fprintf(lfp, "%18s%04X", "", laddr); + fprintf(lfp, " %5u %s\n", line, ib); + return; + } + + /* + * Address (with allocation) + */ + fprintf(lfp, " %04X", laddr); + if (lmode == ALIST || lmode == BLIST) { + fprintf(lfp, "%19s%5u %s\n", "", line, ib); + outdot(); + return; + } + wp = cb; + wpt = cbt; + nb = (int) (cp - cb); + + /* + * First line of output for this source line with data. + */ + list1(wp, wpt, nb, 1); + fprintf(lfp, " %5u %s\n", line, ib); + + /* + * Subsequent lines of output if more data. + */ + while ((nb -= 6) > 0) { + wp += 6; + wpt += 6; + slew(lfp, 0); + fprintf(lfp, "%7s", ""); + list1(wp, wpt, nb, 0); + putc('\n', lfp); + } + } else + /* + * OCTAL output Option. + */ + if (xflag == 1) { /* OCTAL */ + /* + * Equate only + */ + if (lmode == ELIST) { + fprintf(lfp, "%16s%06o", "", laddr); + fprintf(lfp, " %5u %s\n", line, ib); + return; + } + + /* + * Address (with allocation) + */ + fprintf(lfp, " %06o", laddr); + if (lmode == ALIST || lmode == BLIST) { + fprintf(lfp, "%17s%5u %s\n", "", line, ib); + outdot(); + return; + } + wp = cb; + wpt = cbt; + nb = (int) (cp - cb); + + /* + * First line of output for this source line with data. + */ + list1(wp, wpt, nb, 1); + fprintf(lfp, " %5u %s\n", line, ib); + + /* + * Subsequent lines of output if more data. + */ + while ((nb -= 4) > 0) { + wp += 4; + wpt += 4; + slew(lfp, 0); + fprintf(lfp, "%9s", ""); + list1(wp, wpt, nb, 0); + putc('\n', lfp); + } + } else + /* + * DECIMAL output Option. + */ + if (xflag == 2) { /* DECIMAL */ + /* + * Equate only + */ + if (lmode == ELIST) { + fprintf(lfp, "%16s%05u", "", laddr); + fprintf(lfp, " %5u %s\n", line, ib); + return; + } + + /* + * Address (with allocation) + */ + fprintf(lfp, " %05u", laddr); + if (lmode == ALIST || lmode == BLIST) { + fprintf(lfp, "%17s%5u %s\n", "", line, ib); + outdot(); + return; + } + wp = cb; + wpt = cbt; + nb = (int) (cp - cb); + + /* + * First line of output for this source line with data. + */ + list1(wp, wpt, nb, 1); + fprintf(lfp, " %5u %s\n", line, ib); + + /* + * Subsequent lines of output if more data. + */ + while ((nb -= 4) > 0) { + wp += 4; + wpt += 4; + slew(lfp, 0); + fprintf(lfp, "%9s", ""); + list1(wp, wpt, nb, 0); + putc('\n', lfp); + } + } +} + +/*)Function VOID list1(wp, wpt, nw, f) + * + * int f fill blank fields (1) + * int nb number of data bytes + * int * wp pointer to data bytes + * int * wpt pointer to data byte mode + * + * local variables: + * int i loop counter + * + * global variables: + * int xflag -x, listing radix flag + * + * functions called: + * VOID list2() asslist.c + * int fprintf() c_library + * + * side effects: + * Data formatted and output to listing. + */ + +VOID +list1(wp, wpt, nb, f) +register char *wp; +register int *wpt, nb, f; +{ + register int i; + + /* + * HEX output Option. + */ + if (xflag == 0) { /* HEX */ + /* + * Bound number of words to HEX maximum per line. + */ + if (nb > 6) + nb = 6; + + /* + * Output bytes. + */ + for (i=0; i 4) + nb = 4; + + /* + * Output bytes. + */ + for (i=0; i 4) + nb = 4; + + /* + * Output bytes. + */ + for (i=0; i= 2) { + if (t & R_RELOC) { + if (t & (R_PAG0|R_PAG)) { + c = '*'; + } else if (t & R_USGN) { + c = 'u'; + } else if (t & R_PCR) { + c = 'p'; + } else { + c = 'r'; + } + if (t & R_HIGH) c += 1; + } + } + + /* + * Output the selected mode. + */ + putc(c, lfp); +} + +/*)Function VOID slew(fp, flag) + * + * FILE * fp file handle for listing + * int flag enable pagination + * + * The function slew() increments the page line count. + * If the page overflows and pagination is enabled: + * 1) put out a page skip, + * 2) a title, + * 3) a subtitle, + * 4) and reset the line count. + * + * local variables: + * none + * + * global variables: + * char cpu[] cpu type string + * int lop current line number on page + * int page current page number + * char stb[] Subtitle string buffer + * char tb[] Title string buffer + * + * functions called: + * int fprintf() c_library + * + * side effects: + * Increments page line counter, on overflow + * a new page header is output to the listing file. + */ + +VOID +slew(fp,flag) +FILE *fp; +int flag; +{ + if ((lop++ >= NLPP) && flag) { + fprintf(fp, "\fASxxxx Assembler %s (%s), page %u.\n", + VERSION, cpu, ++page); + fprintf(fp, "%s\n", tb); + fprintf(fp, "%s\n\n", stb); + lop = 5; + } +} + +/* Used for qsort call in lstsym */ +static int _cmpSym(const void *p1, const void *p2) +{ + struct sym **s1 = (struct sym **)(p1); + struct sym **s2 = (struct sym **)(p2); + return strcmp((*s1)->s_id,(*s2)->s_id); +} + +/*)Function VOID lstsym(fp) + * + * FILE * fp file handle for output + * + * The function lstsym() outputs alphabetically + * sorted symbol and area tables. + * + * local variables: + * int c temporary + * int i loop counter + * int j temporary + * int k temporary + * char * ptr pointer to an id string + * int nmsym number of symbols + * int narea number of areas + * sym * sp pointer to symbol structure + * sym ** p pointer to an array of + * pointers to symbol structures + * area * ap pointer to an area structure + * + * global variables: + * area * areap pointer to an area structure + * char aretbl[] string "Area Table" + * sym dot defined as sym[0] + * char stb[] Subtitle string buffer + * sym * symhash[] array of pointers to NHASH + * linked symbol lists + * char symtbl[] string "Symbol Table" + * FILE * tfp symbol table output file handle + * int xflag -x, listing radix flag + * + * functions called: + * int fprintf() c_library + * int putc() c_library + * VOID slew() aslist.c + * int strcmp() c_library + * char * strcpy() c_library + * + * side effects: + * Symbol and area tables output. + */ + +VOID +lstsym(fp) +FILE *fp; +{ + register int c, i, j, k; + register char *ptr; + int nmsym, narea; + struct sym *sp; + struct sym **p; + struct area *ap; + + /* + * Symbol Table Header + */ + strcpy(stb, &symtbl[0]); + lop = NLPP; + if (fp == tfp) + page = 0; + slew(fp, 1); + + /* + * Find number of symbols + */ + nmsym = 0; + for (i=0; is_sp; + } + } + if (nmsym == 0) + goto atable; + + /* + * Allocate space for an array of pointers to symbols + * and load array. + */ + if ((p = (struct sym **) malloc(sizeof((struct sym *) sp)*nmsym)) + == NULL) { + fprintf(fp, "Insufficient space to build Symbol Table.\n"); + return; + } + nmsym = 0; + for (i=0; is_sp; + } + } + +#if 0 + /* BUBBLE SORT?? WTF??? */ + /* + * Bubble Sort on Symbol Table Array + */ + j = 1; + c = nmsym - 1; + while (j) { + j = 0; + for (i=0; is_id[0],&p[i+1]->s_id[0]) > 0) { + j = 1; + sp = p[i+1]; + p[i+1] = p[i]; + p[i] = sp; + } + } + } +#else + + qsort(p, nmsym, sizeof(struct sym *), _cmpSym); +#endif + + /* + * Symbol Table Output + */ + for (i=0; is_area) { + j = sp->s_area->a_ref; + if (xflag == 0) { + fprintf(fp, " %2X ", j); + } else + if (xflag == 1) { + fprintf(fp, "%3o ", j); + } else + if (xflag == 2) { + fprintf(fp, "%3u ", j); + } + } else { + fprintf(fp, " "); + } + ptr = &sp->s_id[0]; + fprintf(fp, "%-60s", ptr ); /* JLH */ + + if (sp->s_flag & S_ASG) { + putc('=', fp); + } else { + putc(' ', fp); + } + if (sp->s_type == S_NEW) { + if (xflag == 0) { + fprintf(fp, " **** "); + } else + if (xflag == 1) { + fprintf(fp, "****** "); + } else + if (xflag == 2) { + fprintf(fp, " ***** "); + } + } else { + j = sp->s_addr; + if (xflag == 0) { + fprintf(fp, " %04X ", j); + } else + if (xflag == 1) { + fprintf(fp, "%06o ", j); + } else + if (xflag == 2) { + fprintf(fp, " %05u ", j); + } + } + j = 0; + if (sp->s_flag & S_GBL) { + putc('G', fp); + ++j; + } + if (sp->s_area != NULL) { + putc('R', fp); + ++j; + } + if (sp->s_type == S_NEW) { + putc('X', fp); + ++j; + } +#if NCPS-8 + putc('\n', fp); + slew(fp, 0); + ++i; +#else + if (++i % 3 == 0) { + putc('\n', fp); + slew(fp, pflag); + } else + if (i < nmsym) { + while (j++ < 4) + putc(' ', fp); + fprintf(fp, "| "); + } +#endif + } + putc('\n', fp); + + /* + * Area Table Header + */ + +atable: + strcpy(stb, &aretbl[0]); + lop = NLPP; + slew(fp, 1); + + /* + * Area Table Output + */ + narea = 0; + ap = areap; + while (ap) { + ++narea; + ap = ap->a_ap; + } + for (i=0; ia_ap; + j = ap->a_ref; + if (xflag == 0) { + fprintf(fp, " %2X ", j); + } else + if (xflag == 1) { + fprintf(fp, " %3o ", j); + } else + if (xflag == 2) { + fprintf(fp, " %3u ", j); + } + ptr = &ap->a_id[0]; + while (ptr < &ap->a_id[NCPS]) { + if ((c = *ptr++) != 0) { + putc(c, fp); + } else { + putc(' ', fp); + } + } + j = ap->a_size; + k = ap->a_flag; + if (xflag==0) { + fprintf(fp, " size %4X flags %X\n", j, k); + } else + if (xflag==1) { + fprintf(fp, " size %6o flags %o\n", j, k); + } else + if (xflag==2) { + fprintf(fp, " size %5u flags %u\n", j, k); + } + } +} diff --git a/as/hc08/asm.h b/as/hc08/asm.h new file mode 100644 index 00000000..c81374ab --- /dev/null +++ b/as/hc08/asm.h @@ -0,0 +1,679 @@ +/* asm.h */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + * + * 28-Oct-97 JLH: + * - add proto for StoreString + * - change s_id from [NCPS] to pointer + * - change m_id from [NCPS] to pointer + * - change NCPS to 80 + * - case sensitive + * - add R_J11 for 8051 assembler + * - add outr11 prototype for 8051 assembler + * - always define "ccase" + * 2-Nov-97 JLH: + * - add jflag for debug control + * - prototypes for DefineNoICE_Line + * 30-Jan-98 JLH: + * - add memory space flags to a_flag for 8051 + * + * 3-Feb-00 KV: + * - add DS80C390 flat mode support. + */ + +#define VERSION "V01.70 + NoICE + SDCC mods + Flat24 Feb-1999" + +#if !defined(__BORLANDC__) && !defined(_MSC_VER) +#include +#endif + +/* + * Case Sensitivity Flag + */ +#define CASE_SENSITIVE 1 + +/*)Module asm.h + * + * The module asm.h contains the definitions for constants, + * structures, global variables, and ASxxxx functions + * contained in the ASxxxx.c files. The two functions + * and three global variables from the machine dependent + * files are also defined. + */ + +/* + * compiler/operating system specific definitions + */ + +/* DECUS C void definition */ +/* File/extension seperator */ + +#ifdef decus +#define VOID char +#define FSEPX '.' +#endif + +/* PDOS C void definition */ +/* File/extension seperator */ + +#ifdef PDOS +#define VOID char +#define FSEPX ':' +#endif + +/* Default void definition */ +/* File/extension seperator */ + +#ifndef VOID +#define VOID void +#define FSEPX '.' +#define OTHERSYSTEM +#endif + +/* + * PATH_MAX + */ +#include +#ifndef PATH_MAX /* POSIX, but not required */ +#if defined(_MSC_VER) || defined(__BORLANDC__) /* Microsoft C or Borland C*/ +#include +#define PATH_MAX _MAX_PATH +#else +#define PATH_MAX /* define a reasonable value */ +#endif +#endif + +/* + * Assembler definitions. + */ +#define LFTERM '(' /* Left expression delimeter */ +#define RTTERM ')' /* Right expression delimeter */ + +#define NCPS 80 /* Chars. per symbol (JLH: change from 8) */ +#define HUGE 1000 /* A huge number */ +#define NERR 3 /* Errors per line */ +#define NINPUT 1024 /* Input buffer size (icodes need space) */ +#define NCODE 128 /* Listing code buffer size */ +#define NTITL 64 /* Title buffer size */ +#define NSBTL 64 /* SubTitle buffer size */ +#define NHASH 64 /* Buckets in hash table */ +#define HMASK 077 /* Hash mask */ +#define NLPP 60 /* Lines per page */ +#define MAXFIL 6 /* Maximum command line input files */ +#define MAXINC 6 /* Maximum nesting of include files */ +#define MAXIF 10 /* Maximum nesting of if/else/endif */ + +#define NLIST 0 /* No listing */ +#define SLIST 1 /* Source only */ +#define ALIST 2 /* Address only */ +#define BLIST 3 /* Address only with allocation */ +#define CLIST 4 /* Code */ +#define ELIST 5 /* Equate only */ + +#define dot sym[0] /* Dot, current loc */ +#define dca area[0] /* Dca, default code area */ + + +/* NB: for Flat24 extentions to work, Addr_T must be at least 24 + * bits. This is checked at runtime when the .flat24 directive + * is processed. + */ +typedef unsigned int Addr_T; + +/* + * The area structure contains the parameter values for a + * specific program or data section. The area structure + * is a linked list of areas. The initial default area + * is "_CODE" defined in asdata.c, the next area structure + * will be linked to this structure through the structure + * element 'struct area *a_ap'. The structure contains the + * area name, area reference number ("_CODE" is 0) determined + * by the order of .area directives, area size determined + * from the total code and/or data in an area, area fuzz is + * a variable used to track pass to pass changes in the + * area size caused by variable length instruction formats, + * and area flags which specify the area's relocation type. + */ +struct area +{ + struct area *a_ap; /* Area link */ + char a_id[NCPS]; /* Area Name */ + int a_ref; /* Ref. number */ + Addr_T a_size; /* Area size */ + Addr_T a_fuzz; /* Area fuzz */ + int a_flag; /* Area flags */ +}; + +/* + * The "A_" area constants define values used in + * generating the assembler area output data. + * + * Area flags + * + * 7 6 5 4 3 2 1 0 + * +-----+-----+-----+-----+-----+-----+-----+-----+ + * | BIT |XDATA|DATA | PAG | ABS | OVR | | | + * +-----+-----+-----+-----+-----+-----+-----+-----+ + */ + +#define A_CON 0000 /* Concatenating */ +#define A_OVR 0004 /* Overlaying */ +#define A_REL 0000 /* Relocatable */ +#define A_ABS 0010 /* absolute */ +#define A_NOPAG 0000 /* Non-Paged */ +#define A_PAG 0020 /* Paged */ + +/* Additional flags for 8051 address spaces */ +#define A_DATA 0000 /* data space (default)*/ +#define A_CODE 0040 /* code space */ +#define A_XDATA 0100 /* external data space */ +#define A_BIT 0200 /* bit addressable space */ + +/* + * The "R_" relocation constants define values used in + * generating the assembler relocation output data for + * areas, symbols, and code. + * + * Relocation flags + * + * 7 6 5 4 3 2 1 0 + * +-----+-----+-----+-----+-----+-----+-----+-----+ + * | MSB | PAGn| PAG0| USGN| BYT2| PCR | SYM | BYT | + * +-----+-----+-----+-----+-----+-----+-----+-----+ + */ + +#define R_WORD 0x00 /* 16 bit */ +#define R_BYTE 0x01 /* 8 bit */ + +#define R_AREA 0x00 /* Base type */ +#define R_SYM 0x02 + +#define R_NORM 0x00 /* PC adjust */ +#define R_PCR 0x04 + +#define R_BYT1 0x00 /* Byte count for R_BYTE = 1 */ +#define R_BYT2 0x08 /* Byte count for R_BYTE = 2 */ + +#define R_SGND 0x00 /* Signed Byte */ +#define R_USGN 0x10 /* Unsigned Byte */ + +#define R_NOPAG 0x00 /* Page Mode */ +#define R_PAG0 0x20 /* Page '0' */ +#define R_PAG 0x40 /* Page 'nnn' */ + +#define R_LSB 0x00 /* low byte */ +#define R_MSB 0x80 /* high byte */ + +#define R_BYT3 0x100 /* if R_BYTE is set, this is a + * 3 byte address, of which + * the linker must select one byte. + */ +#define R_HIB 0x200 /* If R_BYTE & R_BYT3 are set, linker + * will select byte 3 of the relocated + * 24 bit address. + */ + +#define R_J11 (R_WORD|R_BYT2) /* JLH: 11 bit JMP and CALL (8051) */ +#define R_J19 (R_WORD|R_BYT2|R_MSB) /* 19 bit JMP/CALL (DS80C390) */ +#define R_C24 (R_WORD|R_BYT1|R_MSB) /* 24 bit address (DS80C390) */ +#define R_J19_MASK (R_BYTE|R_BYT2|R_MSB) + +#define IS_R_J19(x) (((x) & R_J19_MASK) == R_J19) +#define IS_R_J11(x) (((x) & R_J19_MASK) == R_J11) +#define IS_C24(x) (((x) & R_J19_MASK) == R_C24) + +#define R_ESCAPE_MASK 0xf0 /* Used to escape relocation modes + * greater than 0xff in the .rel + * file. + */ + +/* + * Listing Control Flags + */ + +#define R_HIGH 0040000 /* High Byte */ +#define R_RELOC 0100000 /* Relocation */ + +#define R_DEF 00 /* Global def. */ +#define R_REF 01 /* Global ref. */ +#define R_REL 00 /* Relocatable */ +#define R_ABS 02 /* Absolute */ +#define R_GBL 00 /* Global */ +#define R_LCL 04 /* Local */ + +/* + * The mne structure is a linked list of the assembler + * mnemonics and directives. The list of mnemonics and + * directives contained in the device dependent file + * xxxpst.c are hashed and linked into NHASH lists in + * module assym.c by syminit(). The structure contains + * the mnemonic/directive name, a subtype which directs + * the evaluation of this mnemonic/directive, a flag which + * is used to detect the end of the mnemonic/directive + * list in xxxpst.c, and a value which is normally + * associated with the assembler mnemonic base instruction + * value. + */ +struct mne +{ + struct mne *m_mp; /* Hash link */ + char *m_id; /* Mnemonic JLH: change from [NCPS] */ + char m_type; /* Mnemonic subtype */ + char m_flag; /* Mnemonic flags */ + Addr_T m_valu; /* Value */ +}; + +/* + * The sym structure is a linked list of symbols defined + * in the assembler source files. The first symbol is "." + * defined in asdata.c. The entry 'struct tsym *s_tsym' + * links any temporary symbols following this symbol and + * preceeding the next normal symbol. The structure also + * contains the symbol's name, type (USER or NEW), flag + * (global, assigned, and multiply defined), a pointer + * to the area structure defining where the symbol is + * located, a reference number assigned by outgsd() in + * asout.c, and the symbols address relative to the base + * address of the area where the symbol is located. + */ +struct sym +{ + struct sym *s_sp; /* Hash link */ + struct tsym *s_tsym; /* Temporary symbol link */ + char *s_id; /* Symbol: JLH change from [NCPS] */ + char s_type; /* Symbol subtype */ + char s_flag; /* Symbol flags */ + struct area *s_area; /* Area line, 0 if absolute */ + int s_ref; /* Ref. number */ + Addr_T s_addr; /* Address */ +}; + +#define S_GBL 01 /* Global */ +#define S_ASG 02 /* Assigned */ +#define S_MDF 04 /* Mult. def */ +#define S_END 010 /* End mark for pst. */ + +#define S_NEW 0 /* New name */ +#define S_USER 1 /* User name */ + /* unused slot */ + /* unused slot */ + /* unused slot */ + +#define S_BYTE 5 /* .byte */ +#define S_WORD 6 /* .word */ +#define S_ASCII 7 /* .ascii */ +#define S_ASCIZ 8 /* .asciz */ +#define S_BLK 9 /* .blkb or .blkw */ +#define S_INCL 10 /* .include */ +#define S_DAREA 11 /* .area */ +#define S_ATYP 12 /* .area type */ +#define S_AREA 13 /* .area name */ +#define S_GLOBL 14 /* .globl */ +#define S_PAGE 15 /* .page */ +#define S_TITLE 16 /* .title */ +#define S_SBTL 17 /* .sbttl */ +#define S_IF 18 /* .if */ +#define S_ELSE 19 /* .else */ +#define S_ENDIF 20 /* .endif */ +#define S_EVEN 21 /* .even */ +#define S_ODD 22 /* .odd */ +#define S_RADIX 23 /* .radix */ +#define S_ORG 24 /* .org */ +#define S_MODUL 25 /* .module */ +#define S_ASCIS 26 /* .ascis */ +#define S_FLAT24 27 /* .flat24 */ +#define S_OPTSDCC 28 /* .optsdcc */ + + +/* + * The tsym structure is a linked list of temporary + * symbols defined in the assembler source files following + * a normal symbol. The structure contains the temporary + * symbols number, a flag (multiply defined), a pointer to the + * area structure defining where the temporary structure + * is located, and the temporary symbol's address relative + * to the base address of the area where the symbol + * is located. + */ +struct tsym +{ + struct tsym *t_lnk; /* Link to next */ +/* sandeep changed to 'int' from 'char' */ +/* this will increase the number temp symbols + that can be defined from 255 to INT_MAX */ + int t_num; /* 0-INT_MAX$ */ + int t_flg; /* flags */ + + struct area *t_area; /* Area */ + Addr_T t_addr; /* Address */ +}; + +/* + * External Definitions for all Global Variables + */ + +extern int aserr; /* ASxxxx error counter + */ +extern jmp_buf jump_env; /* compiler dependent structure + * used by setjmp() and longjmp() + */ +extern int inpfil; /* count of assembler + * input files specified + */ +extern int incfil; /* current file handle index + * for include files + */ +extern int cfile; /* current file handle index + * of input assembly files + */ +extern int flevel; /* IF-ELSE-ENDIF flag will be non + * zero for false conditional case + */ +extern int tlevel; /* current conditional level + */ +extern int ifcnd[MAXIF+1]; /* array of IF statement condition + * values (0 = FALSE) indexed by tlevel + */ +extern int iflvl[MAXIF+1]; /* array of IF-ELSE-ENDIF flevel + * values indexed by tlevel + */ +extern char + afn[PATH_MAX]; /* afile() temporary filespec + */ +extern char + srcfn[MAXFIL][PATH_MAX]; /* array of source file names + */ +extern int + srcline[MAXFIL]; /* current source file line + */ +extern char + incfn[MAXINC][PATH_MAX]; /* array of include file names + */ +extern int + incline[MAXINC]; /* current include file line + */ +extern int radix; /* current number conversion radix: + * 2 (binary), 8 (octal), 10 (decimal), + * 16 (hexadecimal) + */ +extern int line; /* current assembler source + * line number + */ +extern int page; /* current page number + */ +extern int lop; /* current line number on page + */ +extern int pass; /* assembler pass number + */ +extern int lflag; /* -l, generate listing flag + */ +extern int cflag; /* -c, generate sdcdb debug information + */ +extern int gflag; /* -g, make undefined symbols global flag + */ +extern int aflag; /* -a, make all symbols global flag + */ +extern int jflag; /* -j, generate debug information flag + */ +extern int oflag; /* -o, generate relocatable output flag + */ +extern int sflag; /* -s, generate symbol table flag + */ +extern int pflag; /* -p, enable listing pagination + */ +extern int xflag; /* -x, listing radix flag + */ +extern int fflag; /* -f(f), relocations flagged flag + */ +extern Addr_T laddr; /* address of current assembler line + * or value of .if argument + */ +extern Addr_T fuzz; /* tracks pass to pass changes in the + * address of symbols caused by + * variable length instruction formats + */ +extern int lmode; /* listing mode + */ +extern struct area area[]; /* array of 1 area + */ +extern struct area *areap; /* pointer to an area structure + */ +extern struct sym sym[]; /* array of 1 symbol + */ +extern struct sym *symp; /* pointer to a symbol structure + */ +extern struct sym *symhash[NHASH]; /* array of pointers to NHASH + * linked symbol lists + */ +extern struct mne *mnehash[NHASH]; /* array of pointers to NHASH + * linked mnemonic/directive lists + */ +extern char *ep; /* pointer into error list + * array eb[NERR] + */ +extern char eb[NERR]; /* array of generated error codes + */ +extern char *ip; /* pointer into the assembler-source + * text line in ib[] + */ +extern char ib[NINPUT]; /* assembler-source text line + */ +extern char *cp; /* pointer to assembler output + * array cb[] + */ +extern char cb[NCODE]; /* array of assembler output values + */ +extern int *cpt; /* pointer to assembler relocation type + * output array cbt[] + */ +extern int cbt[NCODE]; /* array of assembler relocation types + * describing the data in cb[] + */ +extern char tb[NTITL]; /* Title string buffer + */ +extern char stb[NSBTL]; /* Subtitle string buffer + */ +extern char optsdcc[NINPUT]; /* sdcc compile options + */ +extern int flat24Mode; /* non-zero if we are using DS390 24 bit + * flat mode (via .flat24 directive). + */ +extern char symtbl[]; /* string "Symbol Table" + */ +extern char aretbl[]; /* string "Area Table" + */ +extern char module[NCPS]; /* module name string + */ +extern FILE *lfp; /* list output file handle + */ +extern FILE *ofp; /* relocation output file handle + */ +extern FILE *tfp; /* symbol table output file handle + */ +extern FILE *sfp[MAXFIL]; /* array of assembler-source file handles + */ +extern FILE *ifp[MAXINC]; /* array of include-file file handles + */ +extern unsigned char ctype[128]; /* array of character types, one per + * ASCII character + */ + +extern char ccase[128]; /* an array of characters which + * perform the case translation function + */ +/* + * Definitions for Character Types + */ +#define SPACE 0000 +#define ETC 0000 +#define LETTER 0001 +#define DIGIT 0002 +#define BINOP 0004 +#define RAD2 0010 +#define RAD8 0020 +#define RAD10 0040 +#define RAD16 0100 +#define ILL 0200 + +#define DGT2 DIGIT|RAD16|RAD10|RAD8|RAD2 +#define DGT8 DIGIT|RAD16|RAD10|RAD8 +#define DGT10 DIGIT|RAD16|RAD10 +#define LTR16 LETTER|RAD16 + +/* + * The exp structure is used to return the evaluation + * of an expression. The structure supports three valid + * cases: + * (1) The expression evaluates to a constant, + * mode = S_USER, flag = 0, addr contains the + * constant, and base = NULL. + * (2) The expression evaluates to a defined symbol + * plus or minus a constant, mode = S_USER, + * flag = 0, addr contains the constant, and + * base = pointer to area symbol. + * (3) The expression evaluates to a external + * global symbol plus or minus a constant, + * mode = S_NEW, flag = 1, addr contains the + * constant, and base = pointer to symbol. + */ +struct expr +{ + char e_mode; /* Address mode */ + char e_flag; /* Symbol flag */ + Addr_T e_addr; /* Address */ + union { + struct area *e_ap; + struct sym *e_sp; + } e_base; /* Rel. base */ + int e_rlcf; /* Rel. flags */ +}; + +/* C Library functions */ +/* for reference only +extern VOID exit(); +extern int fclose(); +extern char * fgets(); +extern FILE * fopen(); +extern int fprintf(); +extern VOID longjmp(); +extern VOID * malloc(); +extern int printf(); +extern char putc(); +extern int rewind(); +extern int setjmp(); +extern int strcmp(); +extern char * strcpy(); +extern int strlen(); +extern char * strncpy(); +*/ + +/* Machine independent functions */ + +/* asmain.c */ +extern FILE * afile(); +extern VOID asexit(); +extern VOID asmbl(); +extern int main(); +extern VOID newdot(); +extern VOID phase(); +extern VOID usage(); + +/* aslex.c */ +extern char endline(); +extern char get(); +extern VOID getid(); +extern int getline(); +extern int getmap(); +extern char getnb(); +extern VOID getst(); +extern int more(); +extern VOID unget(); +extern VOID chop_crlf(); + +/* assym.c */ +extern struct area * alookup(); +extern struct mne * mlookup(); +extern int hash(); +extern struct sym * lookup(); +extern VOID * new(); +extern int symeq(); +extern VOID syminit(); +extern VOID symglob(); +extern VOID allglob(); + +/* assubr.c */ +extern VOID aerr(); +extern VOID diag(); +extern VOID err(); +extern VOID warnBanner(void); +extern char * geterr(); +extern VOID qerr(); +extern VOID rerr(); + +/* asexpr.c */ +extern VOID abscheck(); +extern Addr_T absexpr(); +extern VOID clrexpr(); +extern int digit(); +extern int is_abs(); +extern VOID expr(); +extern int oprio(); +extern VOID term(); + +/* aslist.c */ +extern VOID list(); +extern VOID list1(); +extern VOID list2(); +extern VOID lstsym(); +extern VOID slew(); + +/* asout.c */ +extern int hibyte(); +extern int lobyte(); +extern int byte3(int); +extern VOID out(); +extern VOID outab(); +extern VOID outarea(); +extern VOID outaw(); +extern VOID outall(); +extern VOID outdot(); +extern VOID outbuf(); +extern VOID outchk(); +extern VOID outgsd(); +extern VOID outrb(); +extern VOID outrw(struct expr *, int); +extern VOID outr24(struct expr *, int); +extern VOID outsym(); +extern VOID out_lb(); +extern VOID out_lw(); +extern VOID out_l24(int, int); +extern VOID out_rw(); +extern VOID out_tw(); +extern VOID out_t24(int); +extern VOID outr11(); /* JLH */ +extern VOID outr19(struct expr *, int, int); + +/* asstore.c */ +extern char *StoreString( char *str ); + +/* asnoice.c */ +extern void DefineNoICE_Line(); +extern void DefineCDB_Line(); + +/* Machine dependent variables */ + +extern char * cpu; +extern char * dsft; +extern int hilo; +extern struct mne mne[]; + +/* Machine dependent functions */ + +extern VOID minit(); +extern VOID machine(struct mne *); diff --git a/as/hc08/asmain.c b/as/hc08/asmain.c new file mode 100644 index 00000000..cb987f55 --- /dev/null +++ b/as/hc08/asmain.c @@ -0,0 +1,1232 @@ +/* asmain.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + * + * 29-Oct-97 JLH pass ";!" comments to output file + */ + +#include +#include +#include +#include + +#include "asm.h" +#include "strcmpi.h" + +/*)Module asmain.c + * + * The module asmain.c includes the command argument parser, + * the three pass sequencer, and the machine independent + * assembler parsing code. + * + * asmain.c contains the following functions: + * VOID main(argc, argv) + * VOID asexit() + * VOID asmbl() + * FILE * afile(fn, ft, wf) + * VOID newdot(nap) + * VOID phase(ap, a) + * VOID usage() + * + * asmain.c contains the array char *usetxt[] which + * references the usage text strings printed by usage(). + */ + +/*)Function VOID main(argc, argv) + * + * int argc argument count + * char * argv array of pointers to argument strings + * + * The function main() is the entry point to the assembler. + * The purpose of main() is to (1) parse the command line + * arguments for options and source file specifications and + * (2) to process the source files through the 3 pass assembler. + * Before each assembler pass various variables are initialized + * and source files are rewound to their beginning. During each + * assembler pass each assembler-source text line is processed. + * After each assembler pass the assembler information is flushed + * to any opened output files and the if-else-endif processing + * is checked for proper termination. + * + * The function main() is also responsible for opening all + * output files (REL, LST, and SYM), sequencing the global (-g) + * and all-global (-a) variable definitions, and dumping the + * REL file header information. + * + * local variables: + * char * p pointer to argument string + * int c character from argument string + * int i argument loop counter + * area * ap pointer to area structure + * + * global variables: + * int aflag -a, make all symbols global flag + * char afn[] afile() constructed filespec + * area * areap pointer to an area structure + * int cb[] array of assembler output values + * int cbt[] array of assembler relocation types + * describing the data in cb[] + * int cfile current file handle index + * of input assembly files + * int * cp pointer to assembler output array cb[] + * int * cpt pointer to assembler relocation type + * output array cbt[] + * char eb[] array of generated error codes + * char * ep pointer into error list array eb[] + * int fflag -f(f), relocations flagged flag + * int flevel IF-ELSE-ENDIF flag will be non + * zero for false conditional case + * Addr_T fuzz tracks pass to pass changes in the + * address of symbols caused by + * variable length instruction formats + * int gflag -g, make undefined symbols global flag + * char ib[] assembler-source text line + * int inpfil count of assembler + * input files specified + * int ifcnd[] array of IF statement condition + * values (0 = FALSE) indexed by tlevel + * int iflvl[] array of IF-ELSE-ENDIF flevel + * values indexed by tlevel + * int incfil current file handle index + * for include files + * char * ip pointer into the assembler-source + * text line in ib[] + * jmp_buf jump_env compiler dependent structure + * used by setjmp() and longjmp() + * int lflag -l, generate listing flag + * int line current assembler source + * line number + * int lop current line number on page + * int oflag -o, generate relocatable output flag + * int jflag -j, generate debug info flag + * int page current page number + * int pflag enable listing pagination + * int pass assembler pass number + * int radix current number conversion radix: + * 2 (binary), 8 (octal), 10 (decimal), + * 16 (hexadecimal) + * int sflag -s, generate symbol table flag + * char srcfn[][] array of source file names + * int srcline[] current source file line + * char stb[] Subtitle string buffer + * sym * symp pointer to a symbol structure + * int tlevel current conditional level + * int xflag -x, listing radix flag + * FILE * lfp list output file handle + * FILE * ofp relocation output file handle + * FILE * tfp symbol table output file handle + * FILE * sfp[] array of assembler-source file handles + * + * called functions: + * FILE * afile() asmain.c + * VOID allglob() assym.c + * VOID asexit() asmain.c + * VOID diag() assubr.c + * VOID err() assubr.c + * int fprintf() c-library + * int getline() aslex.c + * VOID list() aslist.c + * VOID lstsym() aslist.c + * VOID minit() ___mch.c + * VOID newdot() asmain.c + * VOID outchk() asout.c + * VOID outgsd() asout.c + * int rewind() c-library + * int setjmp() c-library + * VOID symglob() assym.c + * VOID syminit() assym.c + * VOID usage() asmain.c + * + * side effects: + * Completion of main() completes the assembly process. + * REL, LST, and/or SYM files may be generated. + */ + +int fatalErrors=0; +char relFile[128]; + +int +main(argc, argv) +char *argv[]; +{ + register char *p; + register int c, i; + struct area *ap; + + /*fprintf(stdout, "\n");*/ + inpfil = -1; + pflag = 1; + for (i=1; i= 0) + usage(); + ++p; + while ((c = *p++) != 0) + switch(c) { + + case 'a': + case 'A': + ++aflag; + break; + + case 'c': + case 'C': + ++cflag; + break; + + case 'g': + case 'G': + ++gflag; + break; + + case 'j': /* JLH: debug info */ + case 'J': + ++jflag; + ++oflag; /* force object */ + break; + + case 'l': + case 'L': + ++lflag; + break; + + case 'o': + case 'O': + ++oflag; + break; + + case 's': + case 'S': + ++sflag; + break; + + case 'p': + case 'P': + pflag = 0; + break; + + case 'x': + case 'X': + xflag = 0; + break; + + case 'q': + case 'Q': + xflag = 1; + break; + + case 'd': + case 'D': + xflag = 2; + break; + + case 'f': + case 'F': + ++fflag; + break; + + default: + usage(); + } + } else { + if (++inpfil == MAXFIL) { + fprintf(stderr, "too many input files\n"); + asexit(1); + } + sfp[inpfil] = afile(p, "", 0); + strcpy(srcfn[inpfil],afn); + if (inpfil == 0) { + if (lflag) + lfp = afile(p, "lst", 1); + if (oflag) { + ofp = afile(p, "rel", 1); + // save the file name if we have to delete it on error + strcpy(relFile,afn); + } + if (sflag) + tfp = afile(p, "sym", 1); + } + } + } + if (inpfil < 0) + usage(); + syminit(); + for (pass=0; pass<3; ++pass) { + if (gflag && pass == 1) + symglob(); + if (aflag && pass == 1) + allglob(); + if (oflag && pass == 2) + outgsd(); + flevel = 0; + tlevel = 0; + ifcnd[0] = 0; + iflvl[0] = 0; + radix = 10; + srcline[0] = 0; + page = 0; + stb[0] = 0; + lop = NLPP; + cfile = 0; + incfil = -1; + for (i = 0; i <= inpfil; i++) + rewind(sfp[i]); + ap = areap; + while (ap) { + ap->a_fuzz = 0; + ap->a_size = 0; + ap = ap->a_ap; + } + fuzz = 0; + dot.s_addr = 0; + dot.s_area = &dca; + symp = ˙ + minit(); + while (getline()) { + cp = cb; + cpt = cbt; + ep = eb; + ip = ib; + + /* JLH: if line begins with ";!", then + * pass this comment on to the output file + */ + if (oflag && (pass == 1) && + (ip[0] == ';') && (ip[1] == '!')) + { + fprintf(ofp, "%s\n", ip ); + } + + if (setjmp(jump_env) == 0) + asmbl(); + + if (pass == 2) { + diag(); + list(); + } + } + newdot(dot.s_area); /* Flush area info */ + if (flevel || tlevel) + err('i'); + } + if (oflag) + outchk(HUGE, HUGE); /* Flush */ + if (sflag) { + lstsym(tfp); + } else + if (lflag) { + lstsym(lfp); + } + //printf ("aserr: %d\n", aserr); + //printf ("fatalErrors: %d\n", fatalErrors); + asexit(fatalErrors); + return 0; // hush the compiler +} + +/*)Function VOID asexit(i) + * + * int i exit code + * + * The function asexit() explicitly closes all open + * files and then terminates the program. + * + * local variables: + * int j loop counter + * + * global variables: + * FILE * ifp[] array of include-file file handles + * FILE * lfp list output file handle + * FILE * ofp relocation output file handle + * FILE * tfp symbol table output file handle + * FILE * sfp[] array of assembler-source file handles + * + * functions called: + * int fclose() c-library + * VOID exit() c-library + * + * side effects: + * All files closed. Program terminates. + */ + +VOID +asexit(i) +int i; +{ + int j; + + if (lfp != NULL) fclose(lfp); + if (ofp != NULL) fclose(ofp); + if (tfp != NULL) fclose(tfp); + + for (j=0; j= 0) { + n = 10*n + d; + c = get(); + } + if (c != '$' || get() != ':') + qerr(); + tp = symp->s_tsym; + if (pass == 0) { + while (tp) { + if (n == tp->t_num) { + tp->t_flg |= S_MDF; + break; + } + tp = tp->t_lnk; + } + if (tp == NULL) { + tp=(struct tsym *) new (sizeof(struct tsym)); + tp->t_lnk = symp->s_tsym; + tp->t_num = n; + tp->t_flg = 0; + tp->t_area = dot.s_area; + tp->t_addr = dot.s_addr; + symp->s_tsym = tp; + } + } else { + while (tp) { + if (n == tp->t_num) { + break; + } + tp = tp->t_lnk; + } + if (tp) { + if (pass == 1) { + fuzz = tp->t_addr - dot.s_addr; + tp->t_area = dot.s_area; + tp->t_addr = dot.s_addr; + } else { + phase(tp->t_area, tp->t_addr); + if (tp->t_flg & S_MDF) + err('m'); + } + } else { + err('u'); + } + } + lmode = ALIST; + goto loop; + } + /* + * If the first character is a letter then assume a lable, + * symbol, assembler directive, or assembler mnemonic is + * being processed. + */ + if ((ctype[c] & LETTER) == 0) { + if (flevel) { + return; + } else { + qerr(); + } + } + getid(id, c); + c = getnb(); + /* + * If the next character is a : then a label is being processed. + * A double :: defines a global label. If this is new label + * then create a symbol structure. + * pass 0: + * Flag multiply defined labels. + * pass 1: + * Load area, address, and fuzz values + * into structure symp. + * pass 2: + * Check for assembler phase error and + * multiply defined error. + */ + if (c == ':') { + if (flevel) + return; + if ((c = get()) != ':') { + unget(c); + c = 0; + } + symp = lookup(id); + if (symp == &dot) + err('.'); + if (pass == 0) + if ((symp->s_type != S_NEW) && + ((symp->s_flag & S_ASG) == 0)) + symp->s_flag |= S_MDF; + if (pass != 2) { + fuzz = symp->s_addr - dot.s_addr; + symp->s_type = S_USER; + symp->s_area = dot.s_area; + symp->s_addr = dot.s_addr; + } else { + if (symp->s_flag & S_MDF) + err('m'); + phase(symp->s_area, symp->s_addr); + } + if (c) { + symp->s_flag |= S_GBL; + } + lmode = ALIST; + goto loop; + } + /* + * If the next character is a = then an equate is being processed. + * A double == defines a global equate. If this is new variable + * then create a symbol structure. + */ + if (c == '=') { + if (flevel) + return; + if ((c = get()) != '=') { + unget(c); + c = 0; + } + clrexpr(&e1); + expr(&e1, 0); + sp = lookup(id); + if (sp == &dot) { + outall(); + if (e1.e_flag || e1.e_base.e_ap != dot.s_area) + err('.'); + } else + if (sp->s_type != S_NEW && (sp->s_flag & S_ASG) == 0) { + err('m'); + } + sp->s_type = S_USER; + sp->s_area = e1.e_base.e_ap; + sp->s_addr = laddr = e1.e_addr; + sp->s_flag |= S_ASG; + if (c) { + sp->s_flag |= S_GBL; + } + lmode = ELIST; + goto loop; + } + unget(c); + lmode = flevel ? SLIST : CLIST; + if ((mp = mlookup(id)) == NULL) { + if (!flevel) + err('o'); + return; + } + /* + * If we have gotten this far then we have found an + * assembler directive or an assembler mnemonic. + * + * Check for .if, .else, .endif, and .page directives + * which are not controlled by the conditional flags + */ + switch (mp->m_type) { + + case S_IF: + n = absexpr(); + if (tlevel < MAXIF) { + ++tlevel; + ifcnd[tlevel] = n; + iflvl[tlevel] = flevel; + if (n == 0) { + ++flevel; + } + } else { + err('i'); + } + lmode = ELIST; + laddr = n; + return; + + case S_ELSE: + if (ifcnd[tlevel]) { + if (++flevel > (iflvl[tlevel]+1)) { + err('i'); + } + } else { + if (--flevel < iflvl[tlevel]) { + err('i'); + } + } + lmode = SLIST; + return; + + case S_ENDIF: + if (tlevel) { + flevel = iflvl[tlevel--]; + } else { + err('i'); + } + lmode = SLIST; + return; + + case S_PAGE: + lop = NLPP; + lmode = NLIST; + return; + + default: + break; + } + if (flevel) + return; + /* + * If we are not in a false state for .if/.else then + * process the assembler directives here. + */ + switch (mp->m_type) { + + case S_EVEN: + outall(); + laddr = dot.s_addr = (dot.s_addr + 1) & ~1; + lmode = ALIST; + break; + + case S_ODD: + outall(); + laddr = dot.s_addr |= 1; + lmode = ALIST; + break; + + case S_BYTE: + case S_WORD: + do { + clrexpr(&e1); + expr(&e1, 0); + if (mp->m_type == S_BYTE) { + outrb(&e1, R_NORM); + } else { + outrw(&e1, R_NORM); + } + } while ((c = getnb()) == ','); + unget(c); + break; + + case S_ASCII: + case S_ASCIZ: + if ((d = getnb()) == '\0') + qerr(); + while ((c = getmap(d)) >= 0) + outab(c); + if (mp->m_type == S_ASCIZ) + outab(0); + break; + + case S_ASCIS: + if ((d = getnb()) == '\0') + qerr(); + c = getmap(d); + while (c >= 0) { + if ((n = getmap(d)) >= 0) { + outab(c); + } else { + outab(c | 0x80); + } + c = n; + } + break; + + case S_BLK: + clrexpr(&e1); + expr(&e1, 0); + outchk(HUGE,HUGE); + dot.s_addr += e1.e_addr*mp->m_valu; + lmode = BLIST; + break; + + case S_TITLE: + p = tb; + if ((c = getnb()) != 0) { + do { + if (p < &tb[NTITL-1]) + *p++ = c; + } while ((c = get()) != 0); + } + *p = 0; + unget(c); + lmode = SLIST; + break; + + case S_SBTL: + p = stb; + if ((c = getnb()) != 0) { + do { + if (p < &stb[NSBTL-1]) + *p++ = c; + } while ((c = get()) != 0); + } + *p = 0; + unget(c); + lmode = SLIST; + break; + + case S_MODUL: + getst(id, getnb()); // a module can start with a digit + if (pass == 0) { + if (module[0]) { + err('m'); + } else { + strncpy(module, id, NCPS); + } + } + lmode = SLIST; + break; + + case S_OPTSDCC: + p = optsdcc; + if ((c = getnb()) != 0) { + do { + if (p < &optsdcc[NINPUT-1]) + *p++ = c; + } while ((c = get()) != 0); + } + *p = 0; + unget(c); + lmode = SLIST; + /*if (pass == 0) printf("optsdcc=%s\n", optsdcc);*/ + break; + + case S_GLOBL: + do { + getid(id, -1); + sp = lookup(id); + sp->s_flag |= S_GBL; + } while ((c = getnb()) == ','); + unget(c); + lmode = SLIST; + break; + + case S_DAREA: + getid(id, -1); + uaf = 0; + uf = A_CON|A_REL; + if ((c = getnb()) == '(') { + do { + getid(opt, -1); + mp = mlookup(opt); + if (mp && mp->m_type == S_ATYP) { + ++uaf; + uf |= mp->m_valu; + } else { + err('u'); + } + } while ((c = getnb()) == ','); + if (c != ')') + qerr(); + } else { + unget(c); + } + if ((ap = alookup(id)) != NULL) { + if (uaf && uf != ap->a_flag) + err('m'); + } else { + ap = (struct area *) new (sizeof(struct area)); + ap->a_ap = areap; + strncpy(ap->a_id, id, NCPS); + ap->a_ref = areap->a_ref + 1; + ap->a_size = 0; + ap->a_fuzz = 0; + ap->a_flag = uaf ? uf : (A_CON|A_REL); + areap = ap; + } + newdot(ap); + lmode = SLIST; + break; + + case S_ORG: + if (dot.s_area->a_flag & A_ABS) { + outall(); + laddr = dot.s_addr = absexpr(); + } else { + err('o'); + } + outall(); + lmode = ALIST; + break; + + case S_RADIX: + if (more()) { + switch (getnb()) { + case 'b': + case 'B': + radix = 2; + break; + case '@': + case 'o': + case 'O': + case 'q': + case 'Q': + radix = 8; + break; + case 'd': + case 'D': + radix = 10; + break; + case 'h': + case 'H': + case 'x': + case 'X': + radix = 16; + break; + default: + radix = 10; + qerr(); + break; + } + } else { + radix = 10; + } + lmode = SLIST; + break; + + case S_INCL: + d = getnb(); + p = fn; + while ((c = get()) != d) { + if (p < &fn[PATH_MAX-1]) { + *p++ = c; + } else { + break; + } + } + *p = 0; + if (++incfil == MAXINC || + (ifp[incfil] = fopen(fn, "r")) == NULL) { + --incfil; + err('i'); + } else { + lop = NLPP; + incline[incfil] = 0; + strcpy(incfn[incfil],fn); + } + lmode = SLIST; + break; + + case S_FLAT24: + if (more()) + { + getst(id, -1); + + if (!as_strcmpi(id, "on")) + { + /* Quick sanity check: size of + * Addr_T must be at least 24 bits. + */ + if (sizeof(Addr_T) < 3) + { + warnBanner(); + fprintf(stderr, + "Cannot enable Flat24 mode: " + "host system must have 24 bit " + "or greater integers.\n"); + } + else + { + flat24Mode = 1; + } + } + else if (!as_strcmpi(id, "off")) + { + flat24Mode = 0; + } + else + { + qerr(); + } + } + else + { + qerr(); + } + lmode = SLIST; + #if 0 + printf("as8051: ds390 flat mode %sabled.\n", + flat24Mode ? "en" : "dis"); + #endif + break; + + + /* + * If not an assembler directive then go to + * the machine dependent function which handles + * all the assembler mnemonics. + */ + default: + machine(mp); + /* if cdb information the generate the line info */ + if (cflag && (pass == 1)) + DefineCDB_Line(); + + /* JLH: if -j, generate a line number symbol */ + if (jflag && (pass == 1)) + { + DefineNoICE_Line(); + } + + } + goto loop; +} + +/*)Function FILE * afile(fn, ft, wf) + * + * char * fn file specification string + * char * ft file type string + * int wf read(0)/write(1) flag + * + * The function afile() opens a file for reading or writing. + * (1) If the file type specification string ft + * is not NULL then a file specification is + * constructed with the file path\name in fn + * and the extension in ft. + * (2) If the file type specification string ft + * is NULL then the file specification is + * constructed from fn. If fn does not have + * a file type then the default source file + * type dsft is appended to the file specification. + * + * afile() returns a file handle for the opened file or aborts + * the assembler on an open error. + * + * local variables: + * int c character value + * FILE * fp filehandle for opened file + * char * p1 pointer to filespec string fn + * char * p2 pointer to filespec string fb + * char * p3 pointer to filetype string ft + * + * global variables: + * char afn[] afile() constructed filespec + * char dsft[] default assembler file type string + * char afn[] constructed file specification string + * + * functions called: + * VOID asexit() asmain.c + * FILE * fopen() c_library + * int fprintf() c_library + * + * side effects: + * File is opened for read or write. + */ + +FILE * +afile(fn, ft, wf) +char *fn; +char *ft; +int wf; +{ + register char *p2, *p3; + register int c; + FILE *fp; + + p2 = afn; + p3 = ft; + + strcpy (afn, fn); + p2 = strrchr (afn, FSEPX); // search last '.' + if (!p2) + p2 = afn + strlen (afn); + if (p2 > &afn[PATH_MAX-4]) // truncate filename, if it's too long + p2 = &afn[PATH_MAX-4]; + *p2++ = FSEPX; + + // choose a file-extension + if (*p3 == 0) { // extension supplied? + p3 = strrchr (fn, FSEPX); // no: extension in fn? + if (p3) + ++p3; + else + p3 = dsft; // no: default extension + } + + while ((c = *p3++) != 0) { // strncpy + if (p2 < &afn[PATH_MAX-1]) + *p2++ = c; + } + *p2++ = 0; + + if ((fp = fopen(afn, wf?"w":"r")) == NULL) { + fprintf(stderr, "%s: cannot %s.\n", afn, wf?"create":"open"); + asexit(1); + } + return (fp); +} + +/*)Function VOID newdot(nap) + * + * area * nap pointer to the new area structure + * + * The function newdot(): + * (1) copies the current values of fuzz and the last + * address into the current area referenced by dot + * (2) loads dot with the pointer to the new area and + * loads the fuzz and last address parameters + * (3) outall() is called to flush any remaining + * bufferred code from the old area to the output + * + * local variables: + * area * oap pointer to old area + * + * global variables: + * sym dot defined as sym[0] + * Addr_T fuzz tracks pass to pass changes in the + * address of symbols caused by + * variable length instruction formats + * + * functions called: + * none + * + * side effects: + * Current area saved, new area loaded, buffers flushed. + */ + +VOID +newdot(nap) +register struct area *nap; +{ + register struct area *oap; + + oap = dot.s_area; + /* fprintf (stderr, "%s dot.s_area->a_size: %d dot.s_addr: %d\n", + oap->a_id, dot.s_area->a_size, dot.s_addr); */ + oap->a_fuzz = fuzz; + if (oap->a_flag & A_OVR) { + // the size of an overlay is the biggest size encountered + if (oap->a_size < dot.s_addr) { + oap->a_size = dot.s_addr; + } + } else { + oap->a_size = dot.s_addr; + } + if (nap->a_flag & A_OVR) { + // a new overlay starts at 0, no fuzz + dot.s_addr = 0; + fuzz = 0; + } else { + dot.s_addr = nap->a_size; + fuzz = nap->a_fuzz; + } + dot.s_area = nap; + outall(); +} + +/*)Function VOID phase(ap, a) + * + * area * ap pointer to area + * Addr_T a address in area + * + * Function phase() compares the area ap and address a + * with the current area dot.s_area and address dot.s_addr + * to determine if the position of the symbol has changed + * between assembler passes. + * + * local variables: + * none + * + * global varaibles: + * sym * dot defined as sym[0] + * + * functions called: + * none + * + * side effects: + * The p error is invoked if the area and/or address + * has changed. + */ + +VOID +phase(ap, a) +struct area *ap; +Addr_T a; +{ + if (ap != dot.s_area || a != dot.s_addr) + err('p'); +} + +char *usetxt[] = { + "Usage: [-dqxjgalopsf] file1 [file2 file3 ...]", + " d decimal listing", + " q octal listing", + " x hex listing (default)", + " j add line number and debug information to file", /* JLH */ + " g undefined symbols made global", + " a all user symbols made global", + " l create list output file1[LST]", + " o create object output file1[REL]", + " s create symbol output file1[SYM]", + " p disable listing pagination", + " f flag relocatable references by ` in listing file", + " ff flag relocatable references by mode in listing file", + "", + 0 +}; + +/*)Function VOID usage() + * + * The function usage() outputs to the stderr device the + * assembler name and version and a list of valid assembler options. + * + * local variables: + * char ** dp pointer to an array of + * text string pointers. + * + * global variables: + * char cpu[] assembler type string + * char * usetxt[] array of string pointers + * + * functions called: + * VOID asexit() asmain.c + * int fprintf() c_library + * + * side effects: + * program is terminated + */ + +VOID +usage() +{ + register char **dp; + + fprintf(stderr, "\nASxxxx Assembler %s (%s)\n\n", VERSION, cpu); + for (dp = usetxt; *dp; dp++) + fprintf(stderr, "%s\n", *dp); + asexit(1); +} diff --git a/as/hc08/asnoice.c b/as/hc08/asnoice.c new file mode 100644 index 00000000..38d3233f --- /dev/null +++ b/as/hc08/asnoice.c @@ -0,0 +1,122 @@ +/* asnoice.c */ + +/* + * Extensions to CUG 292 assembler ASxxxx to produce NoICE debug files + * + * 3-Nov-1997 by John Hartman + */ + +#include +#include +#include +#include "asm.h" + +/* Return basic file name without path or extension */ +static char* BaseFileName( int fileNumber ); + +char* BaseFileName( int fileNumber ) +{ + static int prevFile = -1; + static char baseName[ PATH_MAX ]; + + char *p1, *p2; + + if (fileNumber != prevFile) + { + prevFile = fileNumber; + + p1 = srcfn[prevFile]; + + /* issue a FILE command with full path and extension */ + fprintf( ofp, ";!FILE %s\n", p1 ); + + /* Name starts after any colon or backslash (DOS) */ + p2 = strrchr( p1, '\\' ); + if (p2 == NULL) p2 = strrchr( p1, '/' ); + if (p2 == NULL) p2 = strrchr( p1, ':' ); + if (p2 == NULL) p2 = p1-1; + strcpy( baseName, p2+1 ); + + /* Name ends at any separator */ + p2 = strrchr( baseName, FSEPX ); + if (p2 != NULL) *p2 = 0; + /* SD comment this out since not a ANSI Function */ + /* strupr( baseName ); */ + } + return baseName; +} + +/* Define a symbol for current location: FILE.line# */ +void DefineNoICE_Line() +{ + char name[ NCPS ]; + struct sym *pSym; + + /* symbol is FILE.nnn */ + sprintf( name, "%s.%u", BaseFileName( cfile ), srcline[ cfile ] ); + + pSym = lookup( name ); + pSym->s_type = S_USER; + pSym->s_area = dot.s_area; + pSym->s_addr = laddr; + pSym->s_flag |= S_GBL; +} + +/* Define a symbol for current location: A$FILE$line# */ +void DefineCDB_Line() +{ + char name[ NCPS ]; + struct sym *pSym; + + /* symbol is FILE.nnn */ + sprintf( name, "A$%s$%u", BaseFileName( cfile ), srcline[ cfile ] ); + + pSym = lookup( name ); + pSym->s_type = S_USER; + pSym->s_area = dot.s_area; + pSym->s_addr = laddr; + pSym->s_flag |= S_GBL; +} + +#if 0 +OLD VERSION +/* Define a symbol for current location: FILE.line# */ +void DefineNoICE_Line() +{ + static int prevFile = -1; + static struct area *pPrevArea = NULL; + static char baseName[ PATH_MAX ]; + + int j; + char *p1, *p2; + + /* Get outfilename without extension for use as base symbol name */ + if (baseName[0] == 0) + { + p1 = srcfn[0]; + p2 = baseName; + while ((*p1 != 0) && (*p1 != FSEPX)) + { + *p2++ = *p1++; + } + *p2 = 0; + /* SD Commented this out since it is not a + ASNI Function */ + /* strupr( baseName ); */ + } + + if ((cfile != prevFile) || (dot.s_area != pPrevArea)) + { + prevFile = cfile; + pPrevArea = dot.s_area; + + /* file or area change: issue FILE command with base @ */ + fprintf( ofp, ";!FILE %s %s_%s\n", srcfn[ cfile ], + baseName, + dot.s_area->a_id ); + } + + fprintf( ofp, ";!LINE %u. 0x%X\n", srcline[ cfile ], laddr ); +} + +#endif diff --git a/as/hc08/asout.c b/as/hc08/asout.c new file mode 100644 index 00000000..363a2c12 --- /dev/null +++ b/as/hc08/asout.c @@ -0,0 +1,1476 @@ +/* asout.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + * + * 28-Oct-97 JLH: + * - outsym: show s_id as string rather than array [NCPS] + * - Added outr11 to support 8051's 11 bit destination address + */ + +#include +#include +#include +#include "asm.h" + + +/*)Module asout.c + * + * The module asout.c contains all the functions used to + * generate the .REL assembler output file. + * + * + * The assemblers' output object file is an ascii file containing + * the information needed by the linker to bind multiple object + * modules into a complete loadable memory image. + * + * The object module contains the following designators: + * + * [XDQ][HL] + * X Hexadecimal radix + * D Decimal radix + * Q Octal radix + * + * H Most significant byte first + * L Least significant byte first + * + * H Header + * M Module + * A Area + * S Symbol + * T Object code + * R Relocation information + * P Paging information + * + * + * (1) Radix Line + * + * The first line of an object module contains the [XDQ][HL] + * format specifier (i.e. XH indicates a hexadecimal file with + * most significant byte first) for the following designators. + * + * + * (2) Header Line + * + * H aa areas gg global symbols + * + * The header line specifies the number of areas(aa) and the + * number of global symbols(gg) defined or referenced in this ob- + * ject module segment. + * + * + * (3) Module Line + * + * M name + * + * The module line specifies the module name from which this + * header segment was assembled. The module line will not appear + * if the .module directive was not used in the source program. + * + * + * (4) Symbol Line + * + * S string Defnnnn + * + * or + * + * S string Refnnnn + * + * The symbol line defines (Def) or references (Ref) the symbol + * 'string' with the value nnnn. The defined value is relative to + * the current area base address. References to constants and ex- + * ternal global symbols will always appear before the first area + * definition. References to external symbols will have a value of + * zero. + * + * + * (5) Area Line + * + * A label size ss flags ff + * + * The area line defines the area label, the size (ss) of the + * area in bytes, and the area flags (ff). The area flags specify + * the ABS, REL, CON, OVR, and PAG parameters: + * + * OVR/CON (0x04/0x00 i.e. bit position 2) + * + * ABS/REL (0x08/0x00 i.e. bit position 3) + * + * PAG (0x10 i.e. bit position 4) + * + * + * (6) T Line + * + * T xx xx nn nn nn nn nn ... + * + * The T line contains the assembled code output by the assem- + * bler with xx xx being the offset address from the current area + * base address and nn being the assembled instructions and data in + * byte format. + * + * + * (7) R Line + * + * R 0 0 nn nn n1 n2 xx xx ... + * + * The R line provides the relocation information to the linker. + * The nn nn value is the current area index, i.e. which area the + * current values were assembled. Relocation information is en- + * coded in groups of 4 bytes: + * + * 1. n1 is the relocation mode and object format + * 1. bit 0 word(0x00)/byte(0x01) + * 2. bit 1 relocatable area(0x00)/symbol(0x02) + * 3. bit 2 normal(0x00)/PC relative(0x04) relocation + * 4. bit 3 1-byte(0x00)/2-byte(0x08) object format for + * byte data + * 5. bit 4 signed(0x00)/unsigned(0x10) byte data + * 6. bit 5 normal(0x00)/page '0'(0x20) reference + * 7. bit 6 normal(0x00)/page 'nnn'(0x40) reference + * 8. bit 7 normal(0x00)/MSB of value + * + * 2. n2 is a byte index into the corresponding (i.e. pre- + * ceeding) T line data (i.e. a pointer to the data to be + * updated by the relocation). The T line data may be + * 1-byte or 2-byte byte data format or 2-byte word + * format. + * + * 3. xx xx is the area/symbol index for the area/symbol be- + * ing referenced. the corresponding area/symbol is found + * in the header area/symbol lists. + * + * + * The groups of 4 bytes are repeated for each item requiring relo- + * cation in the preceeding T line. + * + * + * (8) P Line + * + * P 0 0 nn nn n1 n2 xx xx + * + * The P line provides the paging information to the linker as + * specified by a .setdp directive. The format of the relocation + * information is identical to that of the R line. The correspond- + * ing T line has the following information: + * T xx xx aa aa bb bb + * + * Where aa aa is the area reference number which specifies the + * selected page area and bb bb is the base address of the page. + * bb bb will require relocation processing if the 'n1 n2 xx xx' is + * specified in the P line. The linker will verify that the base + * address is on a 256 byte boundary and that the page length of an + * area defined with the PAG type is not larger than 256 bytes. + * + * The linker defaults any direct page references to the first + * area defined in the input REL file. All ASxxxx assemblers will + * specify the _CODE area first, making this the default page area. + * + * + * asout.c contains the following functions: + * int lobyte() + * int hibyte() + * VOID out() + * VOID outab() + * VOID outall() + * VOID outarea() + * VOID outaw() + * VOID outbuf() + * VOID outchk() + * VOID outdot() + * VOID outdp() + * VOID outgsd() + * VOID outrb() + * VOID outrw() + * VOID outsym() + * VOID out_lb() + * VOID out_lw() + * VOID out_rw() + * VOID out_tw() + * + * The module asout.c contains the following local variables: + * int rel[] relocation data for code/data array + * int * relp pointer to rel array + * int txt[] assembled code/data array + * int * txtp pointer to txt array + */ + +#define NTXT 16 +#define NREL 16 + +char txt[NTXT]; +char rel[NREL]; + +char *txtp = { &txt[0] }; +char *relp = { &rel[0] }; + +/*)Function VOID outab(b) + * + * int b assembler data word + * + * The function outab() processes a single word of + * assembled data in absolute format. + * + * local variables: + * int * txtp pointer to data word + * + * global variables: + * int oflag -o, generate relocatable output flag + * int pass assembler pass number + * + * functions called: + * VOID outchk() asout.c + * VOID out_lb() asout.c + * + * side effects: + * The current assembly address is incremented by 1. + */ + +VOID +outab(b) +{ + if (pass == 2) { + out_lb(b,0); + if (oflag) { + outchk(1, 0); + *txtp++ = lobyte(b); + } + } + ++dot.s_addr; +} + +/*)Function VOID outaw(w) + * + * int w assembler data word + * + * The function outaw() processes a single word of + * assembled data in absolute format. + * + * local variables: + * int * txtp pointer to data word + * + * global variables: + * int oflag -o, generate relocatable output flag + * int pass assembler pass number + * + * functions called: + * VOID outchk() asout.c + * VOID out_lw() asout.c + * + * side effects: + * The current assembly address is incremented by 2. + */ + +VOID +outaw(w) +{ + if (pass == 2) { + out_lw(w,0); + if (oflag) { + outchk(2, 0); + out_tw(w); + } + } + dot.s_addr += 2; +} + +/*)Function VOID write_rmode(r) + * + * int r relocation mode + * + * write_rmode puts the passed relocation mode into the + * output relp buffer, escaping it if necessary. + * + * global variables: + * int * relp pointer to rel array + * + * functions called: + * VOID rerr() assubr.c + * + * side effects: + * relp is incremented appropriately. + */ +VOID +write_rmode(int r) +{ + /* We need to escape the relocation mode if it is greater + * than a byte, or if it happens to look like an escape. + * (I don't think that the latter case is legal, but + * better safe than sorry). + */ + if ((r > 0xff) || ((r & R_ESCAPE_MASK) == R_ESCAPE_MASK)) + { + /* Hack in up to an extra 4 bits of flags with escape. */ + if (r > 0xfff) + { + /* uh-oh.. we have more than 4 extra bits. */ + fprintf(stderr, + "Internal error: relocation mode 0x%X too big.\n", + r); + rerr(); + } + /* printf("escaping relocation mode\n"); */ + *relp++ = R_ESCAPE_MASK | (r >> 8); + *relp++ = r & 0xff; + } + else + { + *relp++ = r; + } +} + +/*)Function VOID outrb(esp, r) + * + * expr * esp pointer to expr structure + * int r relocation mode + * + * The function outrb() processes a byte of generated code + * in either absolute or relocatable format dependent upon + * the data contained in the expr structure esp. If the + * .REL output is enabled then the appropriate information + * is loaded into the txt and rel buffers. + * + * local variables: + * int n symbol/area reference number + * int * relp pointer to rel array + * int * txtp pointer to txt array + * + * global variables: + * sym dot defined as sym[0] + * int oflag -o, generate relocatable output flag + * int pass assembler pass number + * + * functions called: + * VOID aerr() assubr.c + * VOID outchk() asout.c + * VOID out_lb() asout.c + * VOID out_rb() asout.c + * VOID out_tb() asout.c + * + * side effects: + * The current assembly address is incremented by 1. + */ + +VOID +outrb(struct expr *esp, int r) +{ + register int n; + + if (pass == 2) { + if (esp->e_flag==0 && esp->e_base.e_ap==NULL) { + /* This is a constant; simply write the + * const byte to the T line and don't + * generate any relocation info. + */ + out_lb(lobyte(esp->e_addr),0); + if (oflag) { + outchk(1, 0); + *txtp++ = lobyte(esp->e_addr); + } + } else { + /* We are generating a single byte of relocatable + * info. + * + * In 8051 mode, we generate a 16 bit address. The + * linker will later select a single byte based on + * whether R_MSB is set. + * + * In flat24 mode, we generate a 24 bit address. The + * linker will select a single byte based on + * whether R_MSB or R_HIB is set. + */ + if (!flat24Mode) + { + r |= R_BYTE | R_BYT2 | esp->e_rlcf; + if (r & R_MSB) { + out_lb(hibyte(esp->e_addr),r|R_RELOC|R_HIGH); + } else { + out_lb(lobyte(esp->e_addr),r|R_RELOC); + } + if (oflag) { + outchk(2, 5); + out_tw(esp->e_addr); + if (esp->e_flag) { + n = esp->e_base.e_sp->s_ref; + r |= R_SYM; + } else { + n = esp->e_base.e_ap->a_ref; + } + write_rmode(r); + *relp++ = txtp - txt - 2; + out_rw(n); + } + } + else + { + /* 24 bit mode. */ + r |= R_BYTE | R_BYT3 | esp->e_rlcf; + if (r & R_HIB) + { + /* Probably should mark this differently in the + * listing file. + */ + out_lb(byte3(esp->e_addr),r|R_RELOC|R_HIGH); + } + else if (r & R_MSB) { + out_lb(hibyte(esp->e_addr),r|R_RELOC|R_HIGH); + } else { + out_lb(lobyte(esp->e_addr),r|R_RELOC); + } + if (oflag) { + outchk(3, 5); + out_t24(esp->e_addr); + if (esp->e_flag) { + n = esp->e_base.e_sp->s_ref; + r |= R_SYM; + } else { + n = esp->e_base.e_ap->a_ref; + } + write_rmode(r); + *relp++ = txtp - txt - 3; + out_rw(n); + } + } + } + } + ++dot.s_addr; +} + +/*)Function VOID outrw(esp, r) + * + * expr * esp pointer to expr structure + * int r relocation mode + * + * The function outrw() processes a word of generated code + * in either absolute or relocatable format dependent upon + * the data contained in the expr structure esp. If the + * .REL output is enabled then the appropriate information + * is loaded into the txt and rel buffers. + * + * local variables: + * int n symbol/area reference number + * int * relp pointer to rel array + * int * txtp pointer to txt array + * + * global variables: + * sym dot defined as sym[0] + * int oflag -o, generate relocatable output flag + * int pass assembler pass number + * + * functions called: + * VOID aerr() assubr.c + * VOID outchk() asout.c + * VOID out_lw() asout.c + * VOID out_rw() asout.c + * VOID out_tw() asout.c + * + * side effects: + * The current assembly address is incremented by 2. + */ + +VOID +outrw(struct expr *esp, int r) +{ + register int n; + + if (pass == 2) { + + if (esp->e_addr > 0xffff) + { + warnBanner(); + fprintf(stderr, + "large constant 0x%x truncated to 16 bits\n", + esp->e_addr); + } + if (esp->e_flag==0 && esp->e_base.e_ap==NULL) { + out_lw(esp->e_addr,0); + if (oflag) { + outchk(2, 0); + out_tw(esp->e_addr); + } + } else { + r |= R_WORD | esp->e_rlcf; + if (r & R_BYT2) { + rerr(); + if (r & R_MSB) { + out_lw(hibyte(esp->e_addr),r|R_RELOC); + } else { + out_lw(lobyte(esp->e_addr),r|R_RELOC); + } + } else { + out_lw(esp->e_addr,r|R_RELOC); + } + if (oflag) { + outchk(2, 5); + out_tw(esp->e_addr); + if (esp->e_flag) { + n = esp->e_base.e_sp->s_ref; + r |= R_SYM; + } else { + n = esp->e_base.e_ap->a_ref; + } + + if (IS_C24(r)) + { + /* If this happens, the linker will + * attempt to process this 16 bit field + * as 24 bits. That would be bad. + */ + fprintf(stderr, + "***Internal error: C24 out in " + "outrw()\n"); + rerr(); + } + write_rmode(r); + *relp++ = txtp - txt - 2; + out_rw(n); + } + } + } + dot.s_addr += 2; +} + +/*)Function VOID outr24(esp, r) + * + * expr * esp pointer to expr structure + * int r relocation mode + * + * The function outr24() processes 24 bits of generated code + * in either absolute or relocatable format dependent upon + * the data contained in the expr structure esp. If the + * .REL output is enabled then the appropriate information + * is loaded into the txt and rel buffers. + * + * local variables: + * int n symbol/area reference number + * int * relp pointer to rel array + * int * txtp pointer to txt array + * + * global variables: + * sym dot defined as sym[0] + * int oflag -o, generate relocatable output flag + * int pass assembler pass number + * + * functions called: + * VOID aerr() assubr.c + * VOID outchk() asout.c + * VOID out_l24() asout.c + * VOID out_rw() asout.c + * VOID out_t24() asout.c + * + * side effects: + * The current assembly address is incremented by 3. + */ + +VOID +outr24(struct expr *esp, int r) +{ + register int n; + + if (pass == 2) { + if (esp->e_flag==0 && esp->e_base.e_ap==NULL) { + /* This is a constant expression. */ + out_l24(esp->e_addr,0); + if (oflag) { + outchk(3, 0); + out_t24(esp->e_addr); + } + } else { + /* This is a symbol. */ + r |= R_WORD | esp->e_rlcf; + if (r & R_BYT2) { + /* I have no idea what this case is. */ + rerr(); + if (r & R_MSB) { + out_lw(hibyte(esp->e_addr),r|R_RELOC); + } else { + out_lw(lobyte(esp->e_addr),r|R_RELOC); + } + } else { + out_l24(esp->e_addr,r|R_RELOC); + } + if (oflag) { + outchk(3, 5); + out_t24(esp->e_addr); + if (esp->e_flag) { + n = esp->e_base.e_sp->s_ref; + r |= R_SYM; + } else { + n = esp->e_base.e_ap->a_ref; + } + + if (r & R_BYTE) + { + /* If this occurs, we cannot properly + * code the relocation data with the + * R_C24 flag. This means the linker + * will fail to do the 24 bit relocation. + * Which will suck. + */ + fprintf(stderr, + "***Internal error: BYTE out in 24 " + "bit flat mode unexpected.\n"); + rerr(); + } + + write_rmode(r | R_C24); + *relp++ = txtp - txt - 3; + out_rw(n); + } + } + } + dot.s_addr += 3; +} + +/*)Function VOID outdp(carea, esp) + * + * area * carea pointer to current area strcuture + * expr * esp pointer to expr structure + * + * The function outdp() flushes the output buffer and + * outputs paging information to the .REL file. + * + * local variables: + * int n symbol/area reference number + * int r relocation mode + * int * relp pointer to rel array + * int * txtp pointer to txt array + * + * global variables: + * int oflag -o, generate relocatable output flag + * int pass assembler pass number + * + * functions called: + * VOID outbuf() asout.c + * VOID outchk() asout.c + * VOID out_rw() asout.c + * VOID out_tw() asout.c + * + * side effects: + * Output buffer flushed to .REL fiel. + * Paging information dumped to .REL file. + */ + +VOID +outdp(carea, esp) +register struct area *carea; +register struct expr *esp; +{ + register int n, r; + + if (oflag && pass==2) { + outchk(HUGE,HUGE); + out_tw(carea->a_ref); + out_tw(esp->e_addr); + if (esp->e_flag || esp->e_base.e_ap!=NULL) { + r = R_WORD; + if (esp->e_flag) { + n = esp->e_base.e_sp->s_ref; + r |= R_SYM; + } else { + n = esp->e_base.e_ap->a_ref; + } + write_rmode(r); + *relp++ = txtp - txt - 2; + out_rw(n); + } + outbuf("P"); + } +} + +/*)Function VOID outall() + * + * The function outall() will output any bufferred assembled + * data and relocation information (during pass 2 if the .REL + * output has been enabled). + * + * local variables: + * none + * + * global variables: + * int oflag -o, generate relocatable output flag + * int pass assembler pass number + * + * functions called: + * VOID outbuf() asout.c + * + * side effects: + * assembled data and relocation buffers will be cleared. + */ + +VOID +outall() +{ + if (oflag && pass==2) + outbuf("R"); +} + +/*)Function VOID outdot() + * + * The function outdot() outputs information about the + * current program counter value (during pass 2 if the .REL + * output has been enabled). + * + * local variables: + * none + * + * global variables: + * int oflag -o, generate relocatable output flag + * int pass assembler pass number + * + * functions called: + * int fprintf() c_library + * VOID out() asout.c + * + * side effects: + * assembled data and relocation buffers will be cleared. + */ + +VOID +outdot() +{ + if (oflag && pass==2) { + fprintf(ofp, "T"); + out(txt,(int) (txtp-txt)); + fprintf(ofp, "\n"); + fprintf(ofp, "R"); + out(rel,(int) (relp-rel)); + fprintf(ofp, "\n"); + txtp = txt; + relp = rel; + } +} + +/*)Function outchk(nt, nr) + * + * int nr number of additional relocation words + * int nt number of additional data words + * + * The function outchk() checks the data and relocation buffers + * for space to insert the nt data words and nr relocation words. + * If space is not available then output the current data and + * initialize the data buffers to receive the new data. + * + * local variables: + * area * ap pointer to an area structure + * int * relp pointer to rel array + * int * txtp pointer to txt array + * + * global variables: + * sym dot defined as sym[0] + * + * functions called: + * VOID outbuf() asout.c + * + * side effects: + * Data and relocation buffers may be emptied and initialized. + */ + +VOID +outchk(nt, nr) +{ + register struct area *ap; + + if (txtp+nt > &txt[NTXT] || relp+nr > &rel[NREL]) { + outbuf("R"); + } + if (txtp == txt) { + out_tw(dot.s_addr); + if ((ap = dot.s_area) != NULL) { + write_rmode(R_WORD|R_AREA); + *relp++ = 0; + out_rw(ap->a_ref); + } + } +} + +/*)Function VOID outbuf() + * + * The function outbuf() will output any bufferred data + * and relocation information to the .REL file. The output + * buffer pointers and counters are initialized. + * + * local variables: + * int rel[] relocation data for code/data array + * int * relp pointer to rel array + * int txt[] assembled code/data array + * int * txtp pointer to txt array + * + * global variables: + * FILE * ofp relocation output file handle + * + * functions called: + * VOID out() asout.c + * + * side effects: + * All bufferred data written to .REL file and + * buffer pointers and counters initialized. + */ + +VOID +outbuf(s) +char *s; +{ + if (txtp > &txt[2]) { + fprintf(ofp, "T"); + out(txt,(int) (txtp-txt)); + fprintf(ofp, "\n"); + fprintf(ofp, "%s", s); + out(rel,(int) (relp-rel)); + fprintf(ofp, "\n"); + } + txtp = txt; + relp = rel; +} + +/*)Function VOID outgsd() + * + * The function outgsd() performs the following: + * (1) outputs the .REL file radix + * (2) outputs the header specifying the number + * of areas and global symbols + * (3) outputs the module name + * (4) set the reference number and output a symbol line + * for all external global variables and absolutes + * (5) output an area name, set reference number and output + * a symbol line for all global relocatables in the area. + * Repeat this proceedure for all areas. + * + * local variables: + * area * ap pointer to an area structure + * sym * sp pointer to a sym structure + * int i loop counter + * int j loop counter + * int c string character value + * int narea number of code areas + * char * ptr string pointer + * int nglob number of global symbols + * int rn symbol reference number + * + * global variables: + * area * areap pointer to an area structure + * char module[] module name string + * sym * symhash[] array of pointers to NHASH + * linked symbol lists + * int xflag -x, listing radix flag + * + * functions called: + * int fprintf() c_library + * VOID outarea() asout.c + * VOID outsym() asout.c + * int putc() c_library + * + * side effects: + * All symbols are given reference numbers, all symbol + * and area information is output to the .REL file. + */ + +VOID +outgsd() +{ + register struct area *ap; + register struct sym *sp; + register int i, j; + char *ptr; + int c, narea, nglob, rn; + + /* + * Number of areas + */ + narea = areap->a_ref + 1; + + /* + * Number of global references/absolutes + */ + nglob = 0; + for (i = 0; i < NHASH; ++i) { + sp = symhash[i]; + while (sp) { + if (sp->s_flag&S_GBL) + ++nglob; + sp = sp->s_sp; + } + } + + /* + * Output Radix and number of areas and symbols + */ + if (xflag == 0) { + fprintf(ofp, "X%c\n", hilo ? 'H' : 'L'); + fprintf(ofp, "H %X areas %X global symbols\n", narea, nglob); + } else + if (xflag == 1) { + fprintf(ofp, "Q%c\n", hilo ? 'H' : 'L'); + fprintf(ofp, "H %o areas %o global symbols\n", narea, nglob); + } else + if (xflag == 2) { + fprintf(ofp, "D%c\n", hilo ? 'H' : 'L'); + fprintf(ofp, "H %u areas %u global symbols\n", narea, nglob); + } + + /* + * Module name + */ + if (module[0]) { + fprintf(ofp, "M "); + ptr = &module[0]; + while (ptr < &module[NCPS]) { + if ((c = *ptr++) != 0) + putc(c, ofp); + } + putc('\n', ofp); + } + + /* + * Sdcc compile options + */ + if (strlen(optsdcc)) fprintf(ofp, "O %s\n", optsdcc); + + /* + * Global references and absolutes. + */ + rn = 0; + for (i=0; is_area==NULL && sp->s_flag&S_GBL) { + sp->s_ref = rn++; + outsym(sp); + } + sp = sp->s_sp; + } + } + + /* + * Global relocatables. + */ + for (i=0; ia_ref != i) + ap = ap->a_ap; + outarea(ap); + for (j=0; js_area==ap && sp->s_flag&S_GBL) { + sp->s_ref = rn++; + outsym(sp); + } + sp = sp->s_sp; + } + } + } +} + +/*)Function VOID outarea(ap) + * + * area * ap pointer to an area structure + * + * The function outarea() outputs the A line to the .REL + * file. The A line contains the area's name, size, and + * attributes. + * + * local variables: + * char * ptr pointer to area id string + * int c character value + * + * global variables: + * FILE * ofp relocation output file handle + * int xflag -x, listing radix flag + * + * functions called: + * int fprintf() c_library + * int putc() c_library + * + * side effects: + * The A line is sent to the .REL file. + */ + +VOID +outarea(ap) +register struct area *ap; +{ + register char *ptr; + register int c; + + fprintf(ofp, "A "); + ptr = &ap->a_id[0]; + while (ptr < &ap->a_id[NCPS]) { + if ((c = *ptr++) != 0) + putc(c, ofp); + } + if (xflag == 0) { + fprintf(ofp, " size %X flags %X\n", ap->a_size, ap->a_flag); + } else + if (xflag == 1) { + fprintf(ofp, " size %o flags %o\n", ap->a_size, ap->a_flag); + } else + if (xflag == 2) { + fprintf(ofp, " size %u flags %u\n", ap->a_size, ap->a_flag); + } +} + +/*)Function VOID outsym(sp) + * + * sym * sp pointer to a sym structure + * + * The function outsym() outputs the S line to the .REL + * file. The S line contains the symbols name and whether the + * the symbol is defined or referenced. + * + * local variables: + * char * ptr pointer to symbol id string + * int c character value + * + * global variables: + * FILE * ofp relocation output file handle + * int xflag -x, listing radix flag + * + * functions called: + * int fprintf() c_library + * int putc() c_library + * + * side effects: + * The S line is sent to the .REL file. + */ + +VOID +outsym(sp) +register struct sym *sp; +{ + register char *ptr; + + fprintf(ofp, "S "); + ptr = &sp->s_id[0]; + fprintf(ofp, "%s", ptr ); + fprintf(ofp, " %s", sp->s_type==S_NEW ? "Ref" : "Def"); + if (xflag == 0) { + fprintf(ofp, "%04X\n", sp->s_addr); + } else + if (xflag == 1) { + fprintf(ofp, "%06o\n", sp->s_addr); + } else + if (xflag == 2) { + fprintf(ofp, "%05u\n", sp->s_addr); + } +} + +/*)Function VOID out(p, n) + * + * int n number of words to output + * int * p pointer to data words + * + * The function out() outputs the data words to the .REL file + * int the specified radix. + * + * local variables: + * none + * + * global variables: + * FILE * ofp relocation output file handle + * int xflag -x, listing radix flag + * + * functions called: + * int fprintf() c_library + * + * side effects: + * Data is sent to the .REL file. + */ + +VOID +out(char *p, int n) +{ + while (n--) { + if (xflag == 0) { + fprintf(ofp, " %02X", (*p++)&0xff); + } else + if (xflag == 1) { + fprintf(ofp, " %03o", (*p++)&0xff); + } else + if (xflag == 2) { + fprintf(ofp, " %03u", (*p++)&0xff); + } + } +} + +/*)Function VOID out_lb(b, t) + * + * int b assembled data + * int t relocation type + * + * The function out_lb() copies the assembled data and + * its relocation type to the list data buffers. + * + * local variables: + * none + * + * global variables: + * int * cp pointer to assembler output array cb[] + * int * cpt pointer to assembler relocation type + * output array cbt[] + * + * functions called: + * none + * + * side effects: + * Pointers to data and relocation buffers incremented by 1. + */ + +VOID +out_lb(b,t) +register int b,t; +{ + if (cp < &cb[NCODE]) { + *cp++ = b; + *cpt++ = t; + } +} + +/*)Function VOID out_lw(n, t) + * + * int n assembled data + * int t relocation type + * + * The function out_lw() copies the assembled data and + * its relocation type to the list data buffers. + * + * local variables: + * none + * + * global variables: + * int * cp pointer to assembler output array cb[] + * int * cpt pointer to assembler relocation type + * output array cbt[] + * + * functions called: + * none + * + * side effects: + * Pointers to data and relocation buffers incremented by 2. + */ + +VOID +out_lw(n,t) +register int n,t; +{ + if (hilo) { + out_lb(hibyte(n),t ? t|R_HIGH : 0); + out_lb(lobyte(n),t); + } else { + out_lb(lobyte(n),t); + out_lb(hibyte(n),t ? t|R_HIGH : 0); + } +} + +/*)Function VOID out_l24(n, t) + * + * int n assembled data + * int t relocation type + * + * The function out_l24() copies the assembled data and + * its relocation type to the list data buffers. + * + * local variables: + * none + * + * global variables: + * int * cp pointer to assembler output array cb[] + * int * cpt pointer to assembler relocation type + * output array cbt[] + * + * functions called: + * none + * + * side effects: + * Pointers to data and relocation buffers incremented by 3. + */ + +VOID +out_l24(int n, int t) +{ + if (hilo) { + out_lb(byte3(n),t ? t|R_HIGH : 0); + out_lb(hibyte(n),t); + out_lb(lobyte(n),t); + } else { + out_lb(lobyte(n),t); + out_lb(hibyte(n),t); + out_lb(byte3(n),t ? t|R_HIGH : 0); + } +} + +/*)Function VOID out_rw(n) + * + * int n data word + * + * The function out_rw() outputs the relocation (R) + * data word as two bytes ordered according to hilo. + * + * local variables: + * int * relp pointer to rel array + * + * global variables: + * none + * + * functions called: + * int lobyte() asout.c + * int hibyte() asout.c + * + * side effects: + * Pointer to relocation buffer incremented by 2. + */ + +VOID +out_rw(n) +register int n; +{ + if (hilo) { + *relp++ = hibyte(n); + *relp++ = lobyte(n); + } else { + *relp++ = lobyte(n); + *relp++ = hibyte(n); + } +} + +/*)Function VOID out_tw(n) + * + * int n data word + * + * The function out_tw() outputs the text (T) + * data word as two bytes ordered according to hilo. + * + * local variables: + * int * txtp pointer to txt array + * + * global variables: + * none + * + * functions called: + * int lobyte() asout.c + * int hibyte() asout.c + * + * side effects: + * Pointer to relocation buffer incremented by 2. + */ + +VOID +out_tw(n) +register int n; +{ + if (hilo) { + *txtp++ = hibyte(n); + *txtp++ = lobyte(n); + } else { + *txtp++ = lobyte(n); + *txtp++ = hibyte(n); + } +} + +/*)Function VOID out_t24(n) + * + * int n data word + * + * The function out_t24() outputs the text (T) + * data word as three bytes ordered according to hilo. + * + * local variables: + * int * txtp pointer to txt array + * + * global variables: + * none + * + * functions called: + * int lobyte() asout.c + * int hibyte() asout.c + * + * side effects: + * Pointer to relocation buffer incremented by 3. + */ + +VOID +out_t24(int n) +{ + if (hilo) { + *txtp++ = byte3(n); + *txtp++ = hibyte(n); + *txtp++ = lobyte(n); + } else { + *txtp++ = lobyte(n); + *txtp++ = hibyte(n); + *txtp++ = byte3(n); + } +} + +/*)Function int lobyte(n) + * + * int n data word + * + * The function lobyte() returns the lower byte of + * integer n. + * + * local variables: + * none + * + * global variables: + * none + * + * functions called: + * none + * + * side effects: + * none + */ + +int +lobyte(n) +{ + return (n&0377); +} + +/*)Function int hibyte(n) + * + * int n data word + * + * The function hibyte() returns the higher byte of + * integer n. + * + * local variables: + * none + * + * global variables: + * none + * + * functions called: + * none + * + * side effects: + * none + */ + +int +hibyte(n) +{ + return ((n>>8)&0377); +} + +/*)Function int byte3(n) + * + * int n 24 bit data + * + * The function byte3() returns the MSB of the + * 24 bit integer n. + * + * local variables: + * none + * + * global variables: + * none + * + * functions called: + * none + * + * side effects: + * none + */ +int +byte3(int n) +{ + return ((n >> 16) & 0xff); +} + +/* + * JLH: Output relocatable 11 bit jump/call + * + * This function is derived from outrw(), adding the parameter for the + * 11 bit address. This form of address is used only on the 8051 and 8048. + */ +VOID +outr11(esp, op, r) +register struct expr *esp; +int op; +int r; +{ + register int n; + + if (pass == 2) { + if (esp->e_flag==0 && esp->e_base.e_ap==NULL) { + /* equated absolute destination. Assume value + * relative to current area */ + esp->e_base.e_ap = dot.s_area; + } + + /* Relocatable destination. Build THREE + * byte output: relocatable word, followed + * by op-code. Linker will combine them. + * Listing shows only the address. + */ + r |= R_WORD | esp->e_rlcf; + out_lw(esp->e_addr,r|R_RELOC); + if (oflag) { + outchk(3, 5); + out_tw(esp->e_addr); + *txtp++ = op; + + if (esp->e_flag) { + n = esp->e_base.e_sp->s_ref; + r |= R_SYM; + } else { + n = esp->e_base.e_ap->a_ref; + } + write_rmode(r); + *relp++ = txtp - txt - 3; + out_rw(n); + } + } + dot.s_addr += 2; +} + +/* + * Output relocatable 19 bit jump/call + * + * This function is derived from outrw(), adding the parameter for the + * 19 bit address. This form of address is used only in the DS80C390 + * Flat24 mode. + */ +VOID +outr19(struct expr * esp, int op, int r) +{ + register int n; + + if (pass == 2) { + if (esp->e_flag==0 && esp->e_base.e_ap==NULL) { + /* equated absolute destination. Assume value + * relative to current area */ + esp->e_base.e_ap = dot.s_area; + } + + /* Relocatable destination. Build FOUR + * byte output: relocatable 24-bit entity, followed + * by op-code. Linker will combine them. + * Listing shows only the address. + */ + r |= R_WORD | esp->e_rlcf; + out_l24(esp->e_addr,r|R_RELOC); + if (oflag) { + outchk(4, 5); + out_t24(esp->e_addr); + *txtp++ = op; + + if (esp->e_flag) { + n = esp->e_base.e_sp->s_ref; + r |= R_SYM; + } else { + n = esp->e_base.e_ap->a_ref; + } + write_rmode(r); + *relp++ = txtp - txt - 4; + out_rw(n); + } + } + dot.s_addr += 3; +} diff --git a/as/hc08/asstore.c b/as/hc08/asstore.c new file mode 100644 index 00000000..947c7b81 --- /dev/null +++ b/as/hc08/asstore.c @@ -0,0 +1,44 @@ +/* strstore.c */ + +#include +#include +#include +#include "asm.h" + +/* + * Allocate space for "str", copy str into new space + * Return a pointer to the allocated name, or NULL if out of memory + */ +char *StoreString( char *str ) +{ + /* To avoid wasting memory headers on small allocations, we + / allocate a big chunk and parcel it out as required. + / These static variables remember our hunk + */ + #define STR_STORE_HUNK 2000 + static char *pNextFree = NULL; + static int bytesLeft = 0; + + int length; + char *pStoredString; + + length = strlen( str ) + 1; /* what we need, including null */ + + if (length > bytesLeft) + { + /* no space. Allocate a new hunk. We lose the pointer to any + / old hunk. We don't care, as the names are never deleted. + */ + pNextFree = (char*)new( STR_STORE_HUNK ); + bytesLeft = STR_STORE_HUNK; + } + + /* Copy the name and terminating null into the name store */ + pStoredString = pNextFree; + memcpy( pStoredString, str, length ); + + pNextFree += length; + bytesLeft -= length; + + return pStoredString; +} diff --git a/as/hc08/assubr.c b/as/hc08/assubr.c new file mode 100644 index 00000000..1751c294 --- /dev/null +++ b/as/hc08/assubr.c @@ -0,0 +1,275 @@ +/* assubr.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +#include +#include "asm.h" + +/*)Module assubr.c + * + * The module assubr.c contains the error + * processing routines. + * + * assubr.c contains the following functions: + * VOID aerr() + * VOID diag() + * VOID err() + * VOID qerr() + * VOID rerr() + * + * assubr.c contains the local array of *error[] + */ + +/*)Function VOID err(c) + * + * int c error type character + * + * The function err() logs the error code character + * suppressing duplicate errors. If the error code + * is 'q' then the parse of the current assembler-source + * text line is terminated. + * + * local variables: + * char * p pointer to the error array + * + * global variables: + * char eb[] array of generated error codes + * + * functions called: + * VOID longjmp() c_library + * + * side effects: + * The error code may be inserted into the + * error code array eb[] or the parse terminated. + */ + +VOID +err(c) +register int c; +{ + register char *p; + + aserr++; + p = eb; + while (p < ep) + if (*p++ == c) + return; + if (p < &eb[NERR]) { + *p++ = c; + ep = p; + } + if (c == 'q') + longjmp(jump_env, -1); +} + +/*)Function VOID diag() + * + * The function diag() prints any error codes and + * the source line number to the stderr output device. + * + * local variables: + * char * p pointer to error code array eb[] + * + * global variables: + * int cfile current source file index + * char eb[] array of generated error codes + * char * ep pointer into error list + * int incfile current include file index + * char incfn[] array of include file names + * int incline[] array of include line numbers + * char srcfn[] array of source file names + * int srcline[] array of source line numbers + * FILE * stderr c_library + * + * functions called: + * int fprintf() c_library + * char * geterr() assubr.c + * + * side effects: + * none + */ + +extern int fatalErrors; + +VOID +diag() +{ + register char *p,*errstr; + + if (eb != ep) { + fatalErrors++; + p = eb; + fprintf(stderr, "?ASxxxx-Error-<"); + while (p < ep) { + fprintf(stderr, "%c", *p++); + } + fprintf(stderr, "> in line "); + if (incfil >= 0) { + fprintf(stderr, "%d", incline[incfil]); + fprintf(stderr, " of %s\n", incfn[incfil]); + } else { + fprintf(stderr, "%d", srcline[cfile]); + fprintf(stderr, " of %s\n", srcfn[cfile]); + } + p = eb; + while (p < ep) { + if ((errstr = geterr(*p++)) != NULL) { + fprintf(stderr, " %s\n", errstr); + } + } + } +} + +/*)Function VOID warnBanner() + * + * The function warnBanner() prints a generic warning message + * header (including the current source file/line) and positions + * the output for a more specific warning message. + * + * It is assumed that the call to warnBanner will be followed with + * a fprintf to stderr (or equivalent) with the specific warning + * text. + * + * local variables: + * none + * + * global variables: + * int cfile current source file index + * int incfile current include file index + * char incfn[] array of include file names + * int incline[] array of include line numbers + * char srcfn[] array of source file names + * int srcline[] array of source line numbers + * FILE * stderr c_library + * + * functions called: + * int fprintf() c_library + * + * side effects: + * none + */ +VOID +warnBanner(void) +{ + fprintf(stderr, "?ASxxxx-Warning in line "); + if (incfil >= 0) { + fprintf(stderr, "%d", incline[incfil]); + fprintf(stderr, " of %s\n", incfn[incfil]); + } else { + fprintf(stderr, "%d", srcline[cfile]); + fprintf(stderr, " of %s\n", srcfn[cfile]); + } + fprintf(stderr, " "); +} + +/*)Functions: VOID aerr() + * VOID qerr() + * VOID rerr() + * + * The functions aerr(), qerr(), and rerr() report their + * respective error type. These are included only for + * convenience. + * + * local variables: + * none + * + * global variables: + * none + * + * functions called: + * VOID err() assubr.c + * + * side effects: + * The appropriate error code is inserted into the + * error array and the parse may be terminated. + */ + +/* + * Note an 'r' error. + */ +VOID +rerr() +{ + err('r'); +} + +/* + * Note an 'a' error. + */ +VOID +aerr() +{ + err('a'); +} + +/* + * Note a 'q' error. + */ +VOID +qerr() +{ + err('q'); +} + +/* + * ASxxxx assembler errors + */ +char *errors[] = { + "<.> use \". = . + \" not \". = \"", + " machine specific addressing or addressing mode error", + " direct page boundary error", + " direct page addressing error", + " .include file error or an .if/.endif mismatch", + " multiple definitions error", + " .org in REL area or directive / mnemonic error", + "

phase error: label location changing between passes 2 and 3", + " missing or improper operators, terminators, or delimiters", + " relocation error", + " undefined symbol encountered during assembly", + NULL +}; + +/*)Function: char *getarr(c) + * + * int c the error code character + * + * The function geterr() scans the list of errors returning the + * error string corresponding to the input error character. + * + * local variables: + * int i error index counter + * + * global variables: + * char *errors[] array of pointers to the + * error strings + * + * functions called: + * none + * + * side effects: + * A pointer to the appropriate + * error code string is returned. + */ +char * +geterr(c) +int c; +{ + int i; + + for (i=0; errors[i]!=NULL; i++) { + if (c == errors[i][1]) { + return(errors[i]); + } + } + return(NULL); +} + diff --git a/as/hc08/assym.c b/as/hc08/assym.c new file mode 100644 index 00000000..6f504dea --- /dev/null +++ b/as/hc08/assym.c @@ -0,0 +1,441 @@ +/* assym.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + * + * 28-Oct-97 JLH: + * - lookup: Use StoreString for sym construction + * - change symeq() to do length-independent string compare + * - change hash() to do length-independent hash calculation + * 29-Oct-97 JLH: + * - make mnemonics case insensitive ALWAYS + * - make hash() case-insensitive always + * - replace symeq() call in mlookup with strcmpi + */ + +#include +#include +#include +#if defined(_MSC_VER) +#include +#else +#include +#endif +#include "asm.h" +#include "strcmpi.h" + +/*)Module assym.c + * + * The module assym.c contains the functions that operate + * on the mnemonic/directive and symbol structures. + * + * assym.c contains the following functions: + * VOID allglob() + * area * alookup() + * int hash() + * sym * lookup() + * mne * mlookup() + * VOID * new() + * int symeq() + * VOID syminit() + * VOID symglob() + * + * assym.c contains no local/static variables. + */ + +/*)Function VOID syminit() + * + * The function syminit() is called early in the game + * to set up the hashtables. First all buckets in a + * table are cleared. Then a pass is made through + * the respective symbol lists, linking them into + * their hash buckets. Finally the base area pointer + * is set to 'dca'. + * + * local variables: + * int h computed hash value + * mne * mp pointer to a mne structure + * mne ** mpp pointer to an array of + * mne structure pointers + * sym * sp pointer to a sym structure + * sym ** spp pointer to an array of + * sym structure pointers + * + * global variables: + * area area[] single elememt area array + * area dca defined as area[0] + * mne * mnehash[] array of pointers to NHASH + * linked mnemonic/directive lists + * sym * symhash[] array of pointers to NHASH + * linked symbol lists + * + * functions called: + * none + * + * side effects: + * (1) The symbol hash tables are initialized, + * the only defined symbol is '.'. + * (2) The mnemonic/directive hash tables are + * initialized with the assembler directives + * and mnemonics found in the machine dependent + * file ___pst.c. + * (3) The area pointer is initialized to dca (area[0]). + */ + +VOID +syminit() +{ + register struct mne *mp; + struct mne **mpp; + register struct sym *sp; + struct sym **spp; + register int h; + + mpp = &mnehash[0]; + while (mpp < &mnehash[NHASH]) + *mpp++ = NULL; + mp = &mne[0]; + for (;;) { + h = hash(mp->m_id); + mp->m_mp = mnehash[h]; + mnehash[h] = mp; + if (mp->m_flag&S_END) + break; + ++mp; + } + + spp = &symhash[0]; + while (spp < &symhash[NHASH]) + *spp++ = NULL; + sp = &sym[0]; + for (;;) { + h = hash(sp->s_id); + sp->s_sp = symhash[h]; + symhash[h] = sp; + if (sp->s_flag&S_END) + break; + ++sp; + } + + areap = &dca; +} + +/*)Function area * alookup(id) + * + * char * id area name string + * + * The function alookup() searches the area list for a + * match with id. If the area is defined then a pointer + * to this area is returned else a NULL is returned. + * + * local variables: + * area * ap pointer to area structure + * + * global variables: + * area * areap pointer to an area structure + * + * functions called: + * int symeq() assym.c + * + * side effects: + * none + */ + +struct area * +alookup(id) +char *id; +{ + register struct area *ap; + + ap = areap; + while (ap) { + if (symeq(id, ap->a_id)) { + return (ap); + } + ap = ap->a_ap; + } + return(NULL); +} + +/*)Function mne * mlookup(id) + * + * char * id mnemonic/directive name string + * + * The function mlookup() searches the mnemonic/directive + * hash tables for a match returning a pointer to the + * mne structure else it returns a NULL. + * + * local variables: + * mne * mp pointer to mne structure + * int h calculated hash value + * + * global variables: + * mne * mnehash[] array of pointers to NHASH + * linked mnemonic/directive lists + * + * functions called: + * none + * + * side effects: + * none + */ + +struct mne * +mlookup(id) +char *id; +{ + register struct mne *mp; + register int h; + + h = hash(id); + mp = mnehash[h]; + while (mp) { + if (as_strcmpi(id, mp->m_id) == 0) /* JLH: case insensitive */ + return (mp); + mp = mp->m_mp; + } + return (NULL); +} + +/*)Function sym * lookup(id) + * + * char * id symbol name string + * + * The function lookup() searches the symbol hash tables for + * a symbol name match returning a pointer to the sym structure. + * If the symbol is not found then a sym structure is created, + * initialized, and linked to the appropriate hash table. + * A pointer to this new sym structure is returned. + * + * local variables: + * int h computed hash value + * sym * sp pointer to a sym structure + * + * global varaibles: + * sym * symhash[] array of pointers to NHASH + * linked symbol lists + * + * functions called: + * int hash() assym.c + * VOID * new() assym.c + * int symeq() assym.c + * + * side effects: + * If the function new() fails to allocate space + * for the new sym structure the assembly terminates. + */ + +struct sym * +lookup(id) +char *id; +{ + register struct sym *sp; + register int h; + + h = hash(id); + sp = symhash[h]; + while (sp) { + if (symeq(id, sp->s_id)) + return (sp); + sp = sp->s_sp; + } + sp = (struct sym *) new (sizeof(struct sym)); + sp->s_sp = symhash[h]; + symhash[h] = sp; + sp->s_tsym = NULL; + sp->s_id = StoreString( id ); /* JLH */ + sp->s_type = S_NEW; + sp->s_flag = 0; + sp->s_area = NULL; + sp->s_ref = 0; + sp->s_addr = 0; + return (sp); +} + +/*)Function VOID symglob() + * + * The function symglob() will mark all symbols of + * type S_NEW as global. Called at the beginning of pass 1 + * if the assembly option -g was specified. + * + * local variables: + * sym * sp pointer to a sym structure + * int i loop index + * + * global variables: + * sym * symhash[] array of pointers to NHASH + * linked symbol lists + * + * functions called: + * none + * + * side effects: + * Symbol types changed. + */ + +VOID +symglob() +{ + register struct sym *sp; + register int i; + + for (i=0; is_type == S_NEW) + sp->s_flag |= S_GBL; + sp = sp->s_sp; + } + } +} + +/*)Function VOID allglob() + * + * The function allglob() will mark all symbols of + * type S_USER as global. Called at the beginning of pass 1 + * if the assembly option -a was specified. + * + * local variables: + * sym * sp pointer to a sym structure + * int i loop index + * + * global variables: + * sym * symhash[] array of pointers to NHASH + * linked symbol lists + * + * functions called: + * none + * + * side effects: + * Symbol types changed. + */ + +VOID +allglob() +{ + register struct sym *sp; + register int i; + + for (i=0; is_type == S_USER) + sp->s_flag |= S_GBL; + sp = sp->s_sp; + } + } +} + +/*)Function int symeq(p1, p2) + * + * char * p1 name string + * char * p2 name string + * + * The function symeq() compares the two name strings for a match. + * The return value is 1 for a match and 0 for no match. + * + * local variables: + * int h loop counter + * + * global variables: + * char ccase[] an array of characters which + * perform the case translation function + * + * functions called: + * none + * + * side effects: + * none + * + */ + +int +symeq(p1, p2) +register char *p1, *p2; +{ +#if CASE_SENSITIVE + return (strcmp( p1, p2 ) == 0); +#else + return (as_strcmpi( p1, p2 ) == 0); +#endif +} + +/*)Function int hash(p) + * + * char * p pointer to string to hash + * + * The function hash() computes a hash code using the sum + * of all characters mod table size algorithm. + * + * local variables: + * int h accumulated character sum + * int n loop counter + * + * global variables: + * char ccase[] an array of characters which + * perform the case translation function + * + * functions called: + * none + * + * side effects: + * none + */ + +int +hash(p) +register char *p; +{ + register int h; + + h = 0; + while (*p) { + /* JLH: case insensitive hash: Doesn't much affect + * hashing, and allows same function for mnemonics and symbols + */ + h += ccase[(int)*p++]; + } + return (h&HMASK); +} + +/*)Function VOID * new(n) + * + * unsigned int n allocation size in bytes + * + * The function new() allocates n bytes of space and returns + * a pointer to this memory. If no space is available the + * assembly is terminated. + * + * local variables: + * VOID * p a general pointer + * + * global variables: + * none + * + * functions called: + * VOID asexit() asmain.c + * int fprintf() c_library + * VOID * malloc() c_library + * + * side effects: + * Memory is allocated, if allocation fails + * the assembly is terminated. + */ + +VOID * +new(n) +unsigned int n; +{ + register VOID *p; + + if ((p = (VOID *) malloc(n)) == NULL) { + fprintf(stderr, "Out of space!\n"); + asexit(1); + } + return (p); +} diff --git a/as/hc08/clean.mk b/as/hc08/clean.mk new file mode 100644 index 00000000..27e35fa6 --- /dev/null +++ b/as/hc08/clean.mk @@ -0,0 +1,26 @@ +# Deleting all files created by building the program +# -------------------------------------------------- +include ../../Makefile.common +PRJDIR = ../.. + +clean: + rm -f *core *[%~] *.[oa] + rm -f .[a-z]*~ + rm -f $(PRJDIR)/bin/as-hc08$(EXEEXT) $(PRJDIR)/bin/link-hc08$(EXEEXT) as-hc08$(EXEEXT) link-hc08$(EXEEXT) + + +# Deleting all files created by configuring or building the program +# ----------------------------------------------------------------- +distclean: clean + rm -f Makefile *.dep + + +# Like clean but some files may still exist +# ----------------------------------------- +mostlyclean: clean + + +# Deleting everything that can reconstructed by this Makefile. It deletes +# everything deleted by distclean plus files created by bison, etc. +# ----------------------------------------------------------------------- +realclean: distclean diff --git a/as/hc08/conf.mk b/as/hc08/conf.mk new file mode 100644 index 00000000..879e9bc8 --- /dev/null +++ b/as/hc08/conf.mk @@ -0,0 +1,10 @@ +# +# Makefile targets to remake configuration +# + +freshconf: Makefile + +Makefile: $(srcdir)/Makefile.in $(PRJDIR)/configure.in + cd $(PRJDIR) && $(SHELL) ./config.status + +# End of conf.mk diff --git a/as/hc08/lkaomf51.c b/as/hc08/lkaomf51.c new file mode 100644 index 00000000..fa009e77 --- /dev/null +++ b/as/hc08/lkaomf51.c @@ -0,0 +1,980 @@ +/*------------------------------------------------------------------------- + lkaomf51.c - Create an absolute object memory format 51 file + + Written By - Jesus Calvino-Fraga, jesusc@ieee.org (2002) + + 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 2, 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, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +-------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include "aslink.h" + +#define EQ(A,B) !strcmp((A),(B)) +#define MEMSIZE 0x10000 +//#define DODUMP 1 + +typedef struct +{ + char PathName[PATH_MAX]; + char ModuleName[PATH_MAX]; +} _infn; + +int numin=0; +_infn * infn=NULL; + +char ihxFileName[PATH_MAX]; +char aomf51FileName[PATH_MAX]; + +typedef struct +{ + char name[0x100]; + int FileNameNumber; + int Procedure;//If the symbol belongs to a function + int Static; //If the symbol is only public on its file + int Address; + int UsageType; +} _symbol; + +int numsym=0; +_symbol * symbol=NULL; + +typedef struct +{ + char name[0x100]; + int FileNameNumber; + int BeginAdd; + int EndAdd; +} _procedure; + +int numproc=0; +_procedure * procedure=NULL; + +typedef struct +{ + int Number; + int Address; + int Procedure; + int FileNameNumber; +} _linenum; + +int numlinenum=0; +_linenum * linenum=NULL; + +typedef struct +{ + char * name; + int usage; +} +_UsageType; + +_UsageType UsageType[]= +{ + {"CSEG", 0}, + {"GSINIT", 0}, + {"GSFINAL", 0}, + {"HOME", 0}, + {"XINIT", 0}, + {"XSEG", 1}, + {"XISEG", 1}, + {"REG_BANK_0", 2}, + {"REG_BANK_1", 2}, + {"REG_BANK_2", 2}, + {"REG_BANK_3", 2}, + {"DSEG", 2}, + {"OSEG", 2}, + {"SSEG", 2}, + {"ISEG", 3}, + {"BSEG", 4}, + {"", 5} /*A typeless number?*/ +}; + +char * UsageTypeName[]={"CODE", "XDATA", "DATA", "IDATA", "BIT", "NUMBER"}; +int AddNumber; +unsigned char * ihxBuff=NULL; +FILE * aomf51out; +int GlobalChkSum=0; +int HexSize, HexBegin=0x10000; + + +void GetName(char * filepath, char * name) +{ + int j, k; + for(j=strlen(filepath); j>0; j--) + if( (filepath[j-1]=='/')||(filepath[j-1]=='\\') ) break; + for(k=0; (filepath[j]!=0)&&(filepath[j]!='.'); j++, k++) + name[k]=filepath[j]; + name[k]=0; +} + +void SaveLinkedFilePath(char * filepath) +{ + int j; + + if((dflag) && (!rflag)) + { + infn=realloc(infn, sizeof(_infn)*(numin+1)); + + strcpy(infn[numin].PathName, filepath); + j=strlen(infn[numin].PathName); + + /*If there is an extension remove it*/ + if(j>=4) + { + if(EQ(&infn[numin].PathName[j-4], ".rel")) + { + infn[numin].PathName[j-4]=0; + } + } + + /*Get the module name=filename, no drive, no dir, no ext*/ + GetName(infn[numin].PathName, infn[numin].ModuleName); + //printf("%s, %s\n", infn[numin].PathName, infn[numin].ModuleName); + + /*Check if this filename is already in*/ + for(j=0; j=0)?procedure[symbol[j].Procedure].name:"GLOBAL", + symbol[j].Address, + k<6?UsageTypeName[k]:"???"); + } + + fprintf(DumpFile,"\nPROCEDURES:\n"); + for(j=0; j %s\n", + linenum[j].Number, + linenum[j].Address, + infn[linenum[j].FileNameNumber].PathName, + (linenum[j].Procedure>=0)?procedure[linenum[j].Procedure].name:"I don't know"); + } + + fclose(DumpFile); +} +#endif + +void OutputAOEMF51(void) +{ + int i, j, k, recsize; + char MHRname[0x100], Mname[0x100]; + + strcpy(aomf51FileName, infn[0].PathName); + + aomf51out=fopen(aomf51FileName, "wb"); + if(aomf51out==NULL) + { + printf("Couldn't create file %s\n", aomf51FileName); + return; + } + + GetName(infn[0].PathName, MHRname); + GlobalChkSum=0; + + /*Module header record*/ + OutputByte(0x02);/*REC TYPE*/ + OutputWord((strlen(MHRname)+1)+3);/*Record Length*/ + OutputName(MHRname);/*Module Name*/ + OutputByte(0xff);/*TRN ID: RL51?*/ + OutputByte(0x00); + OutputChkSum(); + + for(j=0; j2) /*If there are any symbols*/ + { + OutputByte(0x12); /*REC TYPE*/ + OutputWord(recsize);/*Record Length*/ + OutputByte(0x01); /*DEF TYPE: Public symbols*/ + for(k=0; k2) /*If there are any symbols*/ + { + OutputByte(0x12); /*REC TYPE*/ + OutputWord(recsize);/*Record Length*/ + OutputByte(0x00); /*DEF TYPE: Local symbols*/ + for(k=0; k2) /*If there are any symbols*/ + { + OutputByte(0x12); /*REC TYPE*/ + OutputWord(recsize);/*Record Length*/ + OutputByte(0x00); /*DEF TYPE: Local symbols*/ + for(i=0; i2) /*If there are any line numbers*/ + { + OutputByte(0x12); /*REC TYPE*/ + OutputWord(recsize);/*Record Length*/ + OutputByte(0x03); /*DEF TYPE: Line numbers*/ + for(i=0; i|L}$$$(),

,," + char Sfmt[]="%[^$] %c %[^$] %c %[^$] %c %s"; + char c; + char scope[0x100]; + char name[0x100]; + char level[0x100]; + char block[0x100]; + char Bfmt[]="%[^)] %c %c %c %c %d %c %d"; + char TypeInfo[0x100]; + char AddressSpace; + int OnStack; + int StackOffset; + int Address, CLine; + + if(numin==0) return; + + if (dfp != NULL) + { + fclose(dfp); + dfp=NULL; + } + + /*Build the source filename*/ + strcpy(SourceName, infn[0].PathName); + strcat(SourceName, ".cdb"); + CDBin=fopen(SourceName, "r"); + if(CDBin==NULL) + { + printf("Couldn't open file '%s'\n", SourceName); + lkexit(1); + } + + CurrentModule=0; /*Set the active module as the first one*/ + while(!feof(CDBin)) + { + fgets(buff, sizeof(buff)-1, CDBin); + + if(!feof(CDBin)) switch(buff[0]) + { + /*Example: "M:adq"*/ + case 'M': + sscanf(&buff[2], "%s", name); + for(j=0; j(),
,,*/ + sscanf(block, Bfmt, + TypeInfo, &c, &c, + &AddressSpace, &c, + &OnStack, &c, + &StackOffset); + + i=-1; k=-1; + switch(scope[2]) + { + case 'G': /*Global symbol*/ + break; + case 'L': /*Local symbol of a procedure*/ + for(j=0; j=procedure[k].BeginAdd) && + (linenum[j].Address<=procedure[k].EndAdd) && + (linenum[j].FileNameNumber==procedure[k].FileNameNumber) ) + { + linenum[j].Procedure=k; + } + } + } + + fclose(CDBin); +} + +int hex2dec (char hex_digit) +{ + int j; + j=toupper(hex_digit)-'0'; + if (j>9) j -= 7; + return j; +} + +unsigned char GetByte(char * buffer) +{ + return hex2dec(buffer[0])*0x10+hex2dec(buffer[1]); +} + +unsigned short GetWord(char * buffer) +{ + return hex2dec(buffer[0])*0x1000+ + hex2dec(buffer[1])*0x100+ + hex2dec(buffer[2])*0x10+ + hex2dec(buffer[3]); +} + +int ReadHexFile(int * Begin) +{ + char buffer[1024]; + FILE * filein; + int j; + unsigned char linesize, recordtype, rchksum, value; + unsigned short address; + int MaxAddress=0; + int chksum; + + /*If the hexfile is already open, close it*/ + if(ofp!=NULL) + { + fclose(ofp); + ofp=NULL; + } + + strcpy(ihxFileName, infn[0].PathName); + strcat(ihxFileName, ".ihx"); + + if ( (filein=fopen(ihxFileName, "r")) == NULL ) + { + printf("Error: Can't open file `%s`.\r\n", ihxFileName); + return 0; + } + + ihxBuff=calloc(MEMSIZE, sizeof(unsigned char)); + if(ihxBuff==NULL) + { + printf("Insufficient memory\n"); + fclose(filein); + return -1; + } + + for(j=0; j +#include +#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() + * + * 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 tha 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 + * int i counter, loop variable, value + * char id[] id string + * 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: + * Addr_T 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 + * | | | + * | | `-- ap->a_flag + * | `------------- axp->a_size + * `------------------------- ap->a_id + * + */ +VOID +newarea() +{ + register int i, narea; + struct areax *taxp; + struct areax **halp; + char id[NCPS]; + + /* + * 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 (i && (ap->a_flag != i)) { */ +/* fprintf(stderr, "Conflicting flags in area %8s\n", id); */ +/* lkerr++; */ +/* } */ + } + /* + * Place pointer in header area list + */ + if (headp == NULL) { + fprintf(stderr, "No header defined\n"); + lkexit(1); + } + narea = hp->h_narea; + halp = hp->a_list; + for (i=0; i < narea ;++i) { + if (halp[i] == NULL) { + halp[i] = taxp; + return; + } + } + fprintf(stderr, "Header area list overflow\n"); + lkexit(1); +} + +/*)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 * strcpy() c_library + * 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(id) +char *id; +{ + register struct area *tap; + register struct areax *taxp; + + ap = areap; + axp = (struct areax *) new (sizeof(struct areax)); + while (ap) { + if (symeq(id, ap->a_id)) { + 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; + strncpy(ap->a_id, id, NCPS); + 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 ae 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: + * Addr_T 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. + */ + +/* + * Resolve all area addresses. + */ +VOID +lnkarea() +{ + Addr_T rloc[4]; + int locIndex; + char temp[NCPS]; + struct sym *sp; + /*JCF: used to save the REG_BANK_[0-3] and SBIT_BYTES area pointers*/ + struct area *ta[5]; + int j; + + rloc[0] = rloc[1] = rloc[2] = rloc[3] = 0; + ap = areap; + while (ap) { + if (ap->a_flag&A_ABS) { + /* + * Absolute sections + */ + lnksect(ap); + } else { + /* Determine memory space */ + locIndex = 0; + 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 (ap->a_type == 0) { /* JLH */ + ap->a_addr = rloc[ locIndex ]; + ap->a_type = 1; + } + lnksect(ap); + rloc[ locIndex ] = ap->a_addr + ap->a_size; + } + + /* + * Create symbols called: + * s_ the start address of the area + * l_ the length of the area + */ + + if (! symeq(ap->a_id, _abs_)) { + strncpy(temp+2,ap->a_id,NCPS-2); + *(temp+1) = '_'; + + *temp = 's'; + sp = lkpsym(temp, 1); + sp->s_addr = ap->a_addr ; + /* sp->s_axp = ap->a_axp; JLH: was 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; + + } + + /*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")) { + 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 rellocation counter*/ + if ( (ta[j]->a_size==0) && (ta[j-1]->a_size==0) ) + { + rloc[0]-=8; + } + else break; + } + } + ap = ap->a_ap; + } +} + +/*)Function VOID lnksect() + * + * 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: + * Addr_T size size of area + * Addr_T 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 area determined + * and linked into the structures. + */ + +VOID +lnksect(tap) +register struct area *tap; +{ + register Addr_T size, addr; + register struct areax *taxp; + + size = 0; + addr = tap->a_addr; + if ((tap->a_flag&A_PAG) && (addr & 0xFF)) { + fprintf(stderr, + "\n?ASlink-Warning-Paged Area %8s Boundary Error\n", tap->a_id); + lkerr++; + } + taxp = tap->a_axp; + if (tap->a_flag&A_OVR) { + /* + * Overlayed sections + */ + while (taxp) { + taxp->a_addr = addr; + if (taxp->a_size > size) + size = taxp->a_size; + taxp = taxp->a_axp; + } + } else { + /* + * Concatenated sections + */ + while (taxp) { + taxp->a_addr = addr; + addr += taxp->a_size; + size += taxp->a_size; + taxp = taxp->a_axp; + } + } + tap->a_size = size; + if ((tap->a_flag&A_PAG) && (size > 256)) { + fprintf(stderr, + "\n?ASlink-Warning-Paged Area %8s Length Error\n", tap->a_id); + lkerr++; + } +} diff --git a/as/hc08/lkdata.c b/as/hc08/lkdata.c new file mode 100644 index 00000000..d6a35175 --- /dev/null +++ b/as/hc08/lkdata.c @@ -0,0 +1,491 @@ +/* lkdata.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + * + * 28-Oct-97 JLH: + * - change s_id from [NCPS] to pointer (comment) + * 31-Oct-97 JLH: + * - add jflag and jfp for NoICE output + */ + +#include +#include +#include "aslink.h" + +/*)Module lkdata.c + * + * The module lkdata contains the global variables + * and structures used in the linker aslink. + */ + +/* + * Definitions for all Global Variables + */ + +char *_abs_ = { ". .ABS." }; + +int lkerr; /* Linker error flag + */ +char *ip; /* Pointer into the REL file text line in ib[] + */ +char ib[NINPUT]; /* REL file text line + */ +char *rp; /* pointer into the LST file + * text line in rb[] + */ +char rb[NINPUT]; /* LST file text line being + * address relocated + */ + +char sdccopt[NINPUT]=""; +char sdccopt_module[NINPUT]=""; +char curr_module[NINPUT]=""; + +int dflag; /* Debug information output flag + */ +int oflag; /* Output file type flag + */ +int mflag; /* Map output flag + */ +int sflag; /* JCF: Memory usage output flag + */ +int aflag; /* Overlapping area warning flag + */ +int jflag; /* NoICE output flag + */ +int xflag; /* Map file radix type flag + */ +int pflag; /* print linker command file flag + */ +int uflag; /* Listing relocation flag + */ +int rflag; /* Extended linear address record flag. + */ +int radix; /* current number conversion radix: + * 2 (binary), 8 (octal), 10 (decimal), + * 16 (hexadecimal) + */ +int line; /* current line number + */ +int page; /* current page number + */ +int lop; /* current line number on page + */ +int pass; /* linker pass number + */ +int rtcnt; /* count of elements in the + * rtval[] and rtflg[] arrays + */ +Addr_T rtval[NTXT]; /* data associated with relocation + */ +int rtflg[NTXT]; /* indicates if rtval[] value is + * to be sent to the output file. + * (always set in this linker) + */ +int hilo; /* REL file byte ordering + */ +int gline; /* LST file relocation active + * for current line + */ +int gcntr; /* LST file relocation active + * counter + */ +Addr_T iram_size; /* internal ram size + */ +long xram_size=-1; /* external ram size + */ +long code_size=-1; /* code size + */ + +/* + * The structure lfile contains a pointer to a + * file specification string, the file type, and + * a link to the next lfile structure. + * + * struct lfile + * { + * struct lfile *f_flp; lfile link + * int f_type; File type + * char *f_idp; Pointer to file spec + * }; + */ +struct lfile *filep; /* The pointers (lfile *) filep, + * (lfile *) cfp, and (FILE *) sfp + * are used in conjunction with + * the routine getline() to read + * asmlnk commands from + * (1) the standard input or + * (2) or a command file + * and to read the REL files + * sequentially as defined by the + * asmlnk input commands. + * + * The pointer *filep points to the + * beginning of a linked list of + * lfile structures. + */ +struct lfile *cfp; /* The pointer *cfp points to the + * current lfile structure + */ +struct lfile *startp;/* asmlnk startup file structure + */ +struct lfile *linkp; /* pointer to first lfile structure + * containing an input REL file + * specification + */ +struct lfile *lfp; /* pointer to current lfile structure + * being processed by parse() + */ +FILE *ofp; /* Output file handle + * for word formats + */ +FILE *mfp; /* Map output file handle + */ +FILE *jfp; /* NoICE output file handle + */ +FILE *rfp; /* File handle for output + * address relocated ASxxxx + * listing file + */ +FILE *sfp; /* The file handle sfp points to the + * currently open file + */ +FILE *tfp; /* File handle for input + * ASxxxx listing file + */ +FILE *dfp = NULL ; /* + * File handle for debug + * information output file + */ +/* + * The structures of head, area, areax, and sym are created + * as the REL files are read during the first pass of the + * linker. The struct head is created upon encountering a + * H directive in the REL file. The structure contains a + * link to a link file structure (struct lfile) which describes + * the file containing the H directive, the number of data/code + * areas contained in this header segment, the number of + * symbols referenced/defined in this header segment, a pointer + * to an array of pointers to areax structures (struct areax) + * created as each A directive is read, and a pointer to an + * array of pointers to symbol structures (struct sym) for + * all referenced/defined symbols. As H directives are read + * from the REL files a linked list of head structures is + * created by placing a link to the new head structure + * in the previous head structure. + * + * struct head + * { + * struct head *h_hp; Header link + * struct lfile *h_lfile; Associated file + * int h_narea; # of areas + * struct areax **a_list; Area list + * int h_nglob; # of global symbols + * struct sym **s_list; Global symbol list + * char m_id[NCPS]; Module name + * }; + */ +struct head *headp; /* The pointer to the first + * head structure of a linked list + */ +struct head *hp; /* Pointer to the current + * head structure + */ + +/* + * A structure area is created for each 'unique' data/code + * area definition found as the REL files are read. The + * struct area contains the name of the area, a flag byte + * which contains the area attributes (REL/CON/OVR/ABS), + * an area subtype (not used in this assembler), and the + * area base address and total size which will be filled + * in at the end of the first pass through the REL files. + * As A directives are read from the REL files a linked + * list of unique area structures is created by placing a + * link to the new area structure in the previous area structure. + * + * struct area + * { + * struct area *a_ap; Area link + * struct areax *a_axp; Area extension link + * Addr_T a_addr; Beginning address of area + * Addr_T a_size; Total size of the area + * char a_type; Area subtype + * char a_flag; Flag byte + * char a_id[NCPS]; Name + * }; + */ +struct area *areap; /* The pointer to the first + * area structure of a linked list + */ +struct area *ap; /* Pointer to the current + * area structure + */ + +/* + * An areax structure is created for every A directive found + * while reading the REL files. The struct areax contains a + * link to the 'unique' area structure referenced by the A + * directive and to the head structure this area segment is + * a part of. The size of this area segment as read from the + * A directive is placed in the areax structure. The beginning + * address of this segment will be filled in at the end of the + * first pass through the REL files. As A directives are read + * from the REL files a linked list of areax structures is + * created for each unique area. The final areax linked + * list has at its head the 'unique' area structure linked + * to the linked areax structures (one areax structure for + * each A directive for this area). + * + * struct areax + * { + * struct areax *a_axp; Area extension link + * struct area *a_bap; Base area link + * struct head *a_bhp; Base header link + * Addr_T a_addr; Beginning address of section + * Addr_T a_size; Size of the area in section + * }; + */ +struct areax *axp; /* Pointer to the current + * areax structure + */ + +/* + * A sym structure is created for every unique symbol + * referenced/defined while reading the REL files. The + * struct sym contains the symbol's name, a flag value + * (not used in this linker), a symbol type denoting + * referenced/defined, and an address which is loaded + * with the relative address within the area in which + * the symbol was defined. The sym structure also + * contains a link to the area where the symbol was defined. + * The sym structures are linked into linked lists using + * the symbol link element. + * + * struct sym + * { + * struct sym *s_sp; Symbol link + * struct areax *s_axp; Symbol area link + * char s_type; Symbol subtype + * char s_flag; Flag byte + * Addr_T s_addr; Address + * char *s_id; Name (JLH) + * }; + */ +struct sym *symhash[NHASH]; /* array of pointers to NHASH + * linked symbol lists + */ +/* + * The struct base contains a pointer to a + * base definition string and a link to the next + * base structure. + * + * struct base + * { + * struct base *b_base; Base link + * char *b_strp; String pointer + * }; + */ +struct base *basep; /* The pointer to the first + * base structure + */ +struct base *bsp; /* Pointer to the current + * base structure + */ + +/* + * The struct globl contains a pointer to a + * global definition string and a link to the next + * global structure. + * + * struct globl + * { + * struct globl *g_globl; Global link + * char *g_strp; String pointer + * }; + */ +struct globl *globlp;/* The pointer to the first + * globl structure + */ +struct globl *gsp; /* Pointer to the current + * globl structure + */ + +/* + * A structure sdp is created for each 'unique' paged + * area definition found as the REL files are read. + * As P directives are read from the REL files a linked + * list of unique sdp structures is created by placing a + * link to the new sdp structure in the previous area structure. + * + * struct sdp + * { + * struct area *s_area; Paged Area link + * struct areax *s_areax; Paged Area Extension Link + * Addr_T s_addr; Page address offset + * }; + */ +struct sdp sdp; /* Base Page Structure */ + +/* + * The structure rerr is loaded with the information + * required to report an error during the linking + * process. The structure contains an index value + * which selects the areax structure from the header + * areax structure list, a mode value which selects + * symbol or area relocation, the base address in the + * area section, an area/symbol list index value, and + * an area/symbol offset value. + * + * struct rerr + * { + * int aindex; Linking area + * int mode; Relocation mode + * Addr_T rtbase; Base address in section + * int rindex; Area/Symbol reloaction index + * Addr_T rval; Area/Symbol offset value + * }; + */ +struct rerr rerr; /* Structure containing the + * linker error information + */ + +/* + * The structure lbpath is created for each library + * path specification input by the -k option. The + * lbpath structures are linked into a list using + * the next link element. + * + * struct lbpath { + * struct lbpath *next; + * char *path; + * }; + */ +struct lbpath *lbphead; /* pointer to the first + * library path structure + */ + +/* + * The structure lbname is created for all combinations of the + * library path specifications (input by the -k option) and the + * library file specifications (input by the -l option) that + * lead to an existing file. The element path points to + * the path string, element libfil points to the library + * file string, and the element libspc is the concatenation + * of the valid path and libfil strings. + * + * The lbpath structures are linked into a list + * using the next link element. + * + * Each library file contains a list of object files + * that are contained in the particular library. e.g.: + * + * \iolib\termio + * \inilib\termio + * + * Only one specification per line is allowed. + * + * struct lbname { + * struct lbname *next; + * char *path; + * char *libfil; + * char *libspc; + * }; + */ +struct lbname *lbnhead; /* pointer to the first + * library name structure + */ + +/* + * The function fndsym() searches through all combinations of the + * library path specifications (input by the -k option) and the + * library file specifications (input by the -l option) that + * lead to an existing file for a symbol definition. + * + * The structure lbfile is created for the first library + * object file which contains the definition for the + * specified undefined symbol. + * + * The element libspc points to the library file path specification + * and element relfil points to the object file specification string. + * The element filspc is the complete path/file specification for + * the library file to be imported into the linker. The + * file specicifation may be formed in one of two ways: + * + * (1) If the library file contained an absolute + * path/file specification then this becomes filspc. + * (i.e. C:\...) + * + * (2) If the library file contains a relative path/file + * specification then the concatenation of the path + * and this file specification becomes filspc. + * (i.e. \...) + * + * The lbpath structures are linked into a list + * using the next link element. + * + * struct lbfile { + * struct lbfile *next; + * char *libspc; + * char *relfil; + * char *filspc; + * }; + */ +struct lbfile *lbfhead; /* pointer to the first + * library file structure + */ + +/* + * array of character types, one per + * ASCII character + */ +unsigned char ctype[128] = { +/*NUL*/ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, +/*BS*/ ILL, SPACE, ILL, ILL, SPACE, ILL, ILL, ILL, +/*DLE*/ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, +/*CAN*/ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, +/*SPC*/ SPACE, ETC, ETC, ETC, LETTER, BINOP, BINOP, ETC, +/*(*/ ETC, ETC, BINOP, BINOP, ETC, BINOP, LETTER, BINOP, +/*0*/ DGT2, DGT2, DGT8, DGT8, DGT8, DGT8, DGT8, DGT8, +/*8*/ DGT10, DGT10, ETC, ETC, BINOP, ETC, BINOP, ETC, +/*@*/ ETC, LTR16, LTR16, LTR16, LTR16, LTR16, LTR16, LETTER, +/*H*/ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/*P*/ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/*X*/ LETTER, LETTER, LETTER, ETC, ETC, ETC, BINOP, LETTER, +/*`*/ ETC, LTR16, LTR16, LTR16, LTR16, LTR16, LTR16, LETTER, +/*h*/ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/*p*/ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/*x*/ LETTER, LETTER, LETTER, ETC, BINOP, ETC, ETC, ETC +}; + +/* + * an array of characters which + * perform the case translation function + */ +#if CASE_SENSITIVE +#else +char ccase[128] = { +/*NUL*/ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', +/*BS*/ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', +/*DLE*/ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', +/*CAN*/ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', +/*SPC*/ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', +/*(*/ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', +/*0*/ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', +/*8*/ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', +/*@*/ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', +/*H*/ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', +/*P*/ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', +/*X*/ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', +/*`*/ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', +/*h*/ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', +/*p*/ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', +/*x*/ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177' +}; +#endif diff --git a/as/hc08/lkeval.c b/as/hc08/lkeval.c new file mode 100644 index 00000000..90df0031 --- /dev/null +++ b/as/hc08/lkeval.c @@ -0,0 +1,396 @@ +/* lkeval.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +#include "aslink.h" + +/*)Module lkeval.c + * + * The module lkeval.c contains the routines to evaluate + * arithmetic/numerical expressions. The functions in + * lkeval.c perform a recursive evaluation of the arithmetic + * expression read from the input text line. + * The expression may include binary/unary operators, brackets, + * symbols, labels, and constants in hexadecimal, decimal, octal + * and binary. Arithmetic operations are prioritized and + * evaluated by normal arithmetic conventions. + * + * lkeval.c contains the following functions: + * int digit() + * Addr_T eval() + * Addr_T expr() + * int oprio() + * Addr_T term() + * + * lkeval.c contains no local/static variables + */ + +/*)Function Addr_T eval() + * + * The function eval() evaluates a character string to a + * numerical value. + * + * local variables: + * int c character from input string + * int v value of character in current radix + * Addr_T n evaluation value + * + * global variables: + * int radix current number conversion radix + * + * functions called: + * int digit() lkeval.c + * char get() lklex.c + * char getnb() lklex.c + * VOID unget() lklex.c + * + * side effects: + * Input test is scanned and evaluated to a + * numerical value. + */ + +Addr_T +eval() +{ + register int c, v; + register Addr_T n; + + c = getnb(); + n = 0; + while ((v = digit(c, radix)) >= 0) { + n = n*radix + v; + c = get(); + } + unget(c); + return(n); +} + +/*)Function Addr_T expr(n) + * + * int n a firewall priority; all top + * level calls (from the user) + * should be made with n set to 0. + * + * The function expr() evaluates an expression and + * returns the value. + * + * local variables: + * int c current input text character + * int p current operator priority + * Addr_T v value returned by term() + * Addr_T ve value returned by a + * recursive call to expr() + * + * global variables: + * char ctype[] array of character types, one per + * ASCII character + * int lkerr error flag + * FILE * stderr c_library + * + * functions called: + * VOID expr() lkeval.c + * int fprintf() c_library + * int getnb() lklex.c + * int oprio() lkeval.c + * VOID term() lkeval.c + * VOID unget() lklex.c + * + * + * side effects: + * An expression is evaluated by scanning the input + * text string. + */ + +Addr_T +expr (n) +{ + register int c, p; + register Addr_T v, ve; + + v = term(); + while (ctype[c = getnb()] & BINOP) { + if ((p = oprio(c)) <= n) + break; + if ((c == '>' || c == '<') && c != get()) { + fprintf(stderr, "Invalid expression"); + lkerr++; + return(v); + } + ve = expr(p); + if (c == '+') { + v += ve; + } else + if (c == '-') { + v -= ve; + } else { + switch (c) { + + case '*': + v *= ve; + break; + + case '/': + v /= ve; + break; + + case '&': + v &= ve; + break; + + case '|': + v |= ve; + break; + + case '%': + v %= ve; + break; + + case '^': + v ^= ve; + break; + + case '<': + v <<= ve; + break; + + case '>': + v >>= ve; + break; + } + } + } + unget(c); + return(v); +} + +/*)Function Addr_T term() + * + * The function term() evaluates a single constant + * or symbol value prefaced by any unary operator + * ( +, -, ~, ', ", >, or < ). + * + * local variables: + * int c current character + * char id[] symbol name + * int n value of digit in current radix + * int r current evaluation radix + * sym * sp pointer to a sym structure + * Addr_T v evaluation value + * + * global variables: + * char ctype[] array of character types, one per + * ASCII character + * int lkerr error flag + * + * functions called: + * int digit() lkeval.c + * VOID expr() lkeval.c + * int fprintf() c_library + * int get() lklex.c + * VOID getid() lklex.c + * int getmap() lklex.c + * int getnb() lklex.c + * sym * lkpsym() lksym.c + * Addr_T symval() lksym.c + * VOID unget() lklex.c + * + * side effects: + * An arithmetic term is evaluated by scanning input text. + */ + +Addr_T +term() +{ + register int c, r, n; + register Addr_T v; + struct sym *sp; + char id[NCPS]; + + c = getnb(); + if (c == '#') { c = getnb(); } + if (c == '(') { + v = expr(0); + if (getnb() != ')') { + fprintf(stderr, "Missing delimiter"); + lkerr++; + } + return(v); + } + if (c == '-') { + return(0-expr(100)); + } + if (c == '~') { + return(~expr(100)); + } + if (c == '\'') { + return(getmap(-1)&0377); + } + if (c == '\"') { + if (hilo) { + v = (getmap(-1)&0377)<<8; + v |= getmap(-1)&0377; + } else { + v = getmap(-1)&0377; + v |= (getmap(-1)&0377)<<8; + } + return(v); + } + if (c == '>' || c == '<') { + v = expr(100); + if (c == '>') + v >>= 8; + return(v&0377); + } + if (ctype[c] & DIGIT) { + r = 10; + if (c == '0') { + c = get(); + switch (c) { + case 'b': + case 'B': + r = 2; + c = get(); + break; + case '@': + case 'o': + case 'O': + case 'q': + case 'Q': + r = 8; + c = get(); + break; + case 'd': + case 'D': + r = 10; + c = get(); + break; + case 'h': + case 'H': + case 'x': + case 'X': + r = 16; + c = get(); + break; + default: + break; + } + } + v = 0; + while ((n = digit(c, r)) >= 0) { + v = r*v + n; + c = get(); + } + unget(c); + return(v); + } + if (ctype[c] & LETTER) { + getid(id, c); + if ((sp = lkpsym(id, 0)) == NULL) { + fprintf(stderr, "Undefined symbol %8s\n", id); + lkerr++; + return(0); + } else { + return(symval(sp)); + } + } + return(0); +} + +/*)Function int digit(c, r) + * + * int c digit character + * int r current radix + * + * The function digit() returns the value of c + * in the current radix r. If the c value is not + * a number of the current radix then a -1 is returned. + * + * local variables: + * none + * + * global variables: + * char ctype[] array of character types, one per + * ASCII character + * + * functions called: + * none + * + * side effects: + * none + */ + +int +digit(c, r) +register int c, r; +{ + if (r == 16) { + if (ctype[c] & RAD16) { + if (c >= 'A' && c <= 'F') + return (c - 'A' + 10); + if (c >= 'a' && c <= 'f') + return (c - 'a' + 10); + return (c - '0'); + } + } else + if (r == 10) { + if (ctype[c] & RAD10) + return (c - '0'); + } else + if (r == 8) { + if (ctype[c] & RAD8) + return (c - '0'); + } else + if (r == 2) { + if (ctype[c] & RAD2) + return (c - '0'); + } + return (-1); +} + +/*)Function int oprio(c) + * + * int c operator character + * + * The function oprio() returns a relative priority + * for all valid unary and binary operators. + * + * local variables: + * none + * + * global variables: + * none + * + * functions called: + * none + * + * side effects: + * none + */ + +int +oprio(c) +register int c; +{ + if (c == '*' || c == '/' || c == '%') + return (10); + if (c == '+' || c == '-') + return (7); + if (c == '<' || c == '>') + return (5); + if (c == '^') + return (4); + if (c == '&') + return (3); + if (c == '|') + return (1); + return (0); +} diff --git a/as/hc08/lkhead.c b/as/hc08/lkhead.c new file mode 100644 index 00000000..1cd390ab --- /dev/null +++ b/as/hc08/lkhead.c @@ -0,0 +1,153 @@ +/* lkhead.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +#include "aslink.h" + +/*Module lkhead.c + * + * The module lkhead.c contains the function newhead() which + * creates a head structure and the function module() which + * loads the module name into the current head structure. + * + * lkhead.c contains the following functions: + * VOID newhead() + * VOID module() + * + * lkhead.c contains no local variables. + */ + +/*)Function VOID newhead() + * + * The function newhead() creates a head structure. All head + * structures are linked to form a linked list of head structures + * with the current head structure at the tail of the list. + * + * local variables: + * int i evaluation value + * head * thp temporary pointer + * to a header structure + * + * global variables: + * area *ap Pointer to the current + * area structure + * lfile *cfp The pointer *cfp points to the + * current lfile structure + * head *headp The pointer to the first + * head structure of a linked list + * head *hp Pointer to the current + * head structure + * + * functions called: + * Addr_T expr() lkeval.c + * VOID * new() lksym.c + * VOID lkparea() lkarea.c + * + * side effects: + * A new head structure is created and linked to any + * existing linked head structure. The head structure + * parameters of file handle, number of areas, and number + * of global symbols are loaded into the structure. + * The default area "_abs_" is created when the first + * head structure is created and an areax structure is + * created for every head structure called. + */ + +/* + * Create a new header entry. + * + * H n areas n global symbols + * | | + * | `---- hp->h_nglob + * `------------ hp->h_narea + * + */ +VOID +newhead() +{ + register int i; + struct head *thp; + + hp = (struct head *) new (sizeof(struct head)); + if (headp == NULL) { + headp = hp; + } else { + thp = headp; + while (thp->h_hp) + thp = thp->h_hp; + thp->h_hp = hp; + } + /* + * Set file pointer + */ + hp->h_lfile = cfp; + /* + * Evaluate and build Area pointer list + */ + i = hp->h_narea = eval(); + if (i) + hp->a_list = (struct areax **) new (i*sizeof(struct areax *)); + /* + * Evaluate and build Global symbol pointer list + */ + skip(-1); + i = hp->h_nglob = eval(); + if (i) + hp->s_list = (struct sym **) new (i*sizeof(struct sym *)); + /* + * Setup Absolute DEF linkage. + */ + lkparea(_abs_); + ap->a_flag = A_ABS|A_OVR; +} + +/*)Function VOID module() + * + * The function module() copies the module name into + * the current head structure. + * + * local variables: + * char id[] module id string + * + * global variables: + * head *headp The pointer to the first + * head structure of a linked list + * head *hp Pointer to the current + * head structure + * int lkerr error flag + * FILE * stderr c_library + * + * functions called: + * int fprintf() c_library + * VOID getid() lklex.c + * char * strncpy() c_library + * + * side effects: + * The module name is copied into the head structure. + */ + +/* + * Module Name + */ +VOID +module() +{ + char id[NCPS]; + + if (headp) { + getid(id, -1); + strncpy(hp->m_id, id, NCPS); + } else { + fprintf(stderr, "No header defined\n"); + lkerr++; + } +} diff --git a/as/hc08/lkihx.c b/as/hc08/lkihx.c new file mode 100644 index 00000000..c5890cde --- /dev/null +++ b/as/hc08/lkihx.c @@ -0,0 +1,260 @@ +/* lkihx.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +#include "aslink.h" + +/*)Module lkihx.c + * + * The module lkihx.c contains the function to + * output the relocated object code in the + * Intel Hex format. + * + * lkihx.c contains the following functions: + * VOID hexRecord(addr, rtvalIndex) + * VOID ihx(i) + * VOID ihxEntendedLinearAddress(a) + * + * local variables: hexPageOverrun, lastHexAddr + */ + +/*Intel Hex Format + * Record Mark Field - This field signifies the start of a + * record, and consists of an ascii colon + * (:). + * + * Record Length Field - This field consists of two ascii + * characters which indicate the number of + * data bytes in this record. The + * characters are the result of converting + * the number of bytes in binary to two + * ascii characters, high digit first. An + * End of File record contains two ascii + * zeros in this field. + * + * Load Address Field - This field consists of the four ascii + * characters which result from converting + * the the binary value of the address in + * which to begin loading this record. The + * order is as follows: + * + * High digit of high byte of address. + * Low digit of high byte of address. + * High digit of low byte of address. + * Low digit of low byte of address. + * + * In an End of File record this field con- + * sists of either four ascii zeros or the + * program entry address. Currently the + * entry address option is not supported. + * + * Record Type Field - This field identifies the record type, + * which is either 0 for data records or 1 + * for an End of File record. It consists + * of two ascii characters, with the high + * digit of the record type first, followed + * by the low digit of the record type. + * + * Data Field - This field consists of the actual data, + * converted to two ascii characters, high + * digit first. There are no data bytes in + * the End of File record. + * + * Checksum Field - The checksum field is the 8 bit binary + * sum of the record length field, the load + * address field, the record type field, + * and the data field. This sum is then + * negated (2's complement) and converted + * to two ascii characters, high digit + * first. + */ + +/* Static variable which holds the count of hex page overruns + * (crossings of the 64kB boundary). Cleared at explicit extended + * address output. + */ +static int hexPageOverrun = 0; + +/* Global which holds the last (16 bit) address of hex record. + * Cleared at begin of new area or when the extended address is output. + */ +unsigned int lastHexAddr = 0; + + +/*)Function hexRecord(addr, rtvalIndex) + * + * unsigned addr starting address of hex record + * int rtvalIndex starting index into the rtval[] array + * + * The function hexRecord() outputs the relocated data + * in the standard Intel Hex format (with inserting + * the extended address record if necessary). + * + * local variables: + * Addr_T chksum byte checksum + * int i index for loops + * int overrun temporary storage for hexPageOverrun + * int bytes counter for bytes written + * + * global variables: + * FILE * ofp output file handle + * int rtcnt count of data words + * int rtflg[] output the data flag + * Addr_T rtval[] relocated data + * + * functions called: + * int fprintf() c_library + * ihxEntendedLinearAddress() lkihx.c + * hexRecord() lkihx.c (recursion) + * + * side effects: + * hexPageOverrun is eventually incremented, + * lastHexAddr is updated + */ + +VOID +hexRecord(unsigned addr, int rtvalIndex) +{ + Addr_T chksum; + int i, overrun, bytes; + + for (i = rtvalIndex, chksum = 0; i < rtcnt; i++) { + if (rtflg[i]) { + if (addr + ++chksum > 0xffff) + break; + } + } + if (chksum == 0) + return; // nothing to output + + if (lastHexAddr > addr) { + overrun = hexPageOverrun + 1; + ihxEntendedLinearAddress(lastExtendedAddress + overrun); + hexPageOverrun = overrun; + hexRecord(addr, rtvalIndex); + return; + } + + lastHexAddr = addr; + fprintf(ofp, ":%02X%04X00", chksum, addr); + chksum += (addr >> 8) + (addr & 0xff); + for (i = rtvalIndex, bytes = 0; i < rtcnt; i++) { + if (rtflg[i]) { + fprintf(ofp, "%02X", rtval[i]); + chksum += rtval[i]; +#if 0 + if (addr + ++bytes > 0xffff) { + if (rflag) { + fprintf(ofp, "%02X\n", (0-chksum) & 0xff); + overrun = hexPageOverrun + 1; + ihxEntendedLinearAddress(lastExtendedAddress + overrun); + hexPageOverrun = overrun; + hexRecord(0, i + 1); + return; + } else { + fprintf(stderr, + "warning: extended linear address encountered; " + "you probably want the -r flag.\n"); + } + } +#endif + } + } + fprintf(ofp, "%02X\n", (0-chksum) & 0xff); +} + +/*)Function ihx(i) + * + * int i 0 - process data + * 1 - end of data + * + * The function ihx() calls the hexRecord() function for processing data + * or writes the End of Data record to the file defined by ofp. + * + * local variables: + * Addr_T n auxiliary variable + * + * global variables: + * int hilo byte order + * FILE * ofp output file handle + * Addr_T rtval[] relocated data + * + * functions called: + * VOID hexRecord() lkihx.c + * int fprintf() c_library + * + * side effects: + * The sequence of rtval[0], rtval[1] is eventually changed. + */ + +VOID +ihx(i) +{ + Addr_T n; + if (i) { + if (hilo == 0) { + n = rtval[0]; + rtval[0] = rtval[1]; + rtval[1] = n; + } + hexRecord((rtval[0]<<8) + rtval[1], 2); + } else { + fprintf(ofp, ":00000001FF\n"); + } +} + +/*)Function newArea(i) + * The function newArea() is called when processing of new area is started. + * It resets the value of lastHexAddr. + */ + +VOID +newArea() +{ + lastHexAddr = 0; +} + +/*)Function ihxEntendedLinearAddress(i) + * + * Addr_T i 16 bit extended linear address. + * + * The function ihxEntendedLinearAddress() writes an extended + * linear address record (type 04) to the output file. + * + * local variables: + * Addr_T chksum byte checksum + * + * global variables: + * FILE * ofp output file handle + * + * functions called: + * int fprintf() c_library + * + * side effects: + * The data is output to the file defined by ofp. + * hexPageOverrun and lastHexAddr is cleared + */ +VOID +ihxEntendedLinearAddress(Addr_T a) +{ + Addr_T chksum; + + /* The checksum is the complement of the bytes in the + * record: the 2 is record length, 4 is the extended linear + * address record type, plus the two address bytes. + */ + chksum = 2 + 4 + (a & 0xff) + ((a >> 8) & 0xff); + + fprintf(ofp, ":02000004%04X%02X\n", a & 0xffff, (0-chksum) & 0xff); + hexPageOverrun = 0; + lastHexAddr = 0; +} diff --git a/as/hc08/lklex.c b/as/hc08/lklex.c new file mode 100644 index 00000000..daaa4f32 --- /dev/null +++ b/as/hc08/lklex.c @@ -0,0 +1,637 @@ +/* lklex.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +#include "aslink.h" + +/*)Module lklex.c + * + * The module lklex.c contains the general lexical analysis + * functions used to scan the text lines from the .rel files. + * + * lklex.c contains the fllowing functions: + * char endline() + * char get() + * VOID getfid() + * VOID getid() + * VOID getSid() + * int getline() + * int getmap() + * char getnb() + * int more() + * VOID skip() + * VOID unget() + * + * lklex.c contains no local variables. + */ + +/*)Function VOID getid(id,c) + * + * char * id a pointer to a string of + * maximum length NCPS + * int c mode flag + * >=0 this is first character to + * copy to the string buffer + * <0 skip white space + * + * The function getid() scans the current input text line + * from the current position copying the next LETTER | DIGIT string + * into the external string buffer (id). The string ends when a non + * LETTER or DIGIT character is found. The maximum number of + * characters copied is NCPS. If the input string is larger than + * NCPS characters then the string is truncated, if the input string + * is shorter than NCPS characters then the string is NULL filled. + * If the mode argument (c) is >=0 then (c) is the first character + * copied to the string buffer, if (c) is <0 then intervening white + * space (SPACES and TABS) are skipped. + * + * local variables: + * char * p pointer to external string buffer + * int c current character value + * + * global variables: + * char ctype[] a character array which defines the + * type of character being processed. + * This index is the character + * being processed. + * + * called functions: + * char get() lklex.c + * char getnb() lklex.c + * VOID unget() lklex.c + * + * side effects: + * use of getnb(), get(), and unget() updates the + * global pointer ip the position in the current + * input text line. + */ + +VOID +getid(id, c) +register int c; +char *id; +{ + register char *p; + + if (c < 0) { + c = getnb(); + } + p = id; + do { + if (p < &id[NCPS]) + *p++ = c; + } while (ctype[c=get()] & (LETTER|DIGIT)); + unget(c); + while (p < &id[NCPS]) + *p++ = 0; +} + +/*)Function VOID getSid (char *id) + * + * char * id a pointer to a string of + * maximum length NCPS + * + * getSid is derived from getid. It is called from newsym() + * in lksym.c, when an S-record has to be scanned. getSid accepts + * much more characters than getid, which is necessary for SDCC. + * + * The function getSid() scans the current input text line + * from the current position copying the next string + * into the external string buffer (id). The string ends when a space + * character (space, tab, \0) is found. The maximum number of + * characters copied is NCPS. If the input string is larger than + * NCPS characters then the string is truncated, if the input string + * is shorter than NCPS characters then the string is NULL filled. + * Intervening white space (SPACES and TABS) are skipped. + * + * local variables: + * char * p pointer to external string buffer + * int c current character value + * + * global variables: + * char ctype[] a character array which defines the + * type of character being processed. + * This index is the character + * being processed. + * + * called functions: + * char get() lklex.c + * char getnb() lklex.c + * VOID unget() lklex.c + * + * side effects: + * use of getnb(), get(), and unget() updates the + * global pointer ip the position in the current + * input text line. + */ + +VOID +getSid (id) +char *id; +{ + register int c; + register char *p; + + c = getnb(); + p = id; + do { + if (p < &id[NCPS]) + *p++ = c; + c = get(); + } while (c != '\0' && c != ' ' && c != '\t'); + unget(c); + while (p < &id[NCPS]) + *p++ = 0; +} + +/*)Function VOID getfid(fid,c) + * + * char * str a pointer to a string of + * maximum length PATH_MAX + * int c this is first character to + * copy to the string buffer + * + * The function getfid() scans the current input text line from + * the current position copying the next string into the external + * string buffer (str). The string ends when end of line is found. + * Trailing spacers are removed. The maximum number of characters + * copied is PATH_MAX. If the input string is larger than PATH_MAX + * characters then the string is truncated. The string is NULL + * terminated. + * + * local variables: + * char * p pointer to external string buffer + * int c current character value + * + * global variables: + * char ctype[] a character array which defines the + * type of character being processed. + * This index is the character + * being processed. + * + * called functions: + * char get() lklex.c + * + * side effects: + * use of get() updates the global pointer ip + * the position in the current input text line. + */ + +VOID +getfid(str, c) +register int c; +char *str; +{ + register char *p; + + p = str; + do + { + if (p < &str[PATH_MAX-1]) + *p++ = c; + c = get(); + } while (c); + /* trim trailing spaces */ + --p; + while (p >= str && ctype[(int)*p] == SPACE) + --p; + /* terminate the string */ + *(++p) = '\0'; +} + +/*)Function char getnb() + * + * The function getnb() scans the current input text + * line returning the first character not a SPACE or TAB. + * + * local variables: + * int c current character from input + * + * global variables: + * none + * + * called functions: + * char get() lklex.c + * + * side effects: + * use of get() updates the global pointer ip, the position + * in the current input text line + */ + +char +getnb() +{ + register int c; + + while ((c=get())==' ' || c=='\t') + ; + return (c); +} + +/*)Function VOID skip() + * + * The function skip() scans the input text skipping all + * letters and digits. + * + * local variables: + * none + * + * global variables: + * char ctype[] array of character types, one per + * ASCII character + * + * functions called: + * char get() lklex.c + * char getnb() lklex.c + * VOID unget() lklex.c + * + * side effects: + * Input letters and digits are skipped. + */ + +VOID +skip(c) +register int c; +{ + if (c < 0) + c = getnb(); + while (ctype[c=get()] & (LETTER|DIGIT)) { ; } + unget(c); +} + +/*)Function char get() + * + * The function get() returns the next character in the + * input text line, at the end of the line a + * NULL character is returned. + * + * local variables: + * int c current character from + * input text line + * + * global variables: + * char * ip pointer into the current + * input text line + * + * called functions: + * none + * + * side effects: + * updates ip to the next character position in the + * input text line. If ip is at the end of the + * line, ip is not updated. + */ + +char +get() +{ + register int c; + + if ((c = *ip) != 0) + ++ip; + return (c); +} + +/*)Function VOID unget(c) + * + * int c value of last character + * read from input text line + * + * If (c) is not a NULL character then the global pointer ip + * is updated to point to the preceeding character in the + * input text line. + * + * NOTE: This function does not push the character (c) + * back into the input text line, only + * the pointer ip is changed. + * + * local variables: + * int c last character read + * from input text line + * + * global variables: + * char * ip position into the current + * input text line + * + * called functions: + * none + * + * side effects: + * ip decremented by 1 character position + */ + +VOID +unget(c) +{ + if (c != 0) + --ip; +} + +/*)Function int getmap(d) + * + * int d value to compare with the + * input text line character + * + * The function getmap() converts the 'C' style characters \b, \f, + * \n, \r, and \t to their equivalent ascii values and also + * converts 'C' style octal constants '\123' to their equivalent + * numeric values. If the first character is equivalent to (d) then + * a (-1) is returned, if the end of the line is detected then + * a 'q' error terminates the parse for this line, or if the first + * character is not a \ then the character value is returned. + * + * local variables: + * int c value of character + * from input text line + * int n looping counter + * int v current value of numeric conversion + * + * global variables: + * none + * + * called functions: + * char get() lklex.c + * VOID unget() lklex.c + * + * side effects: + * use of get() updates the global pointer ip the position + * in the current input text line + */ + +int +getmap(d) +{ + register int c, n, v; + + if ((c = get()) == '\0') + return (-1); + if (c == d) + return (-1); + if (c == '\\') { + c = get(); + switch (c) { + + case 'b': + c = '\b'; + break; + + case 'f': + c = '\f'; + break; + + case 'n': + c = '\n'; + break; + + case 'r': + c = '\r'; + break; + + case 't': + c = '\t'; + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + n = 0; + v = 0; + while (++n<=3 && c>='0' && c<='7') { + v = (v<<3) + c - '0'; + c = get(); + } + unget(c); + c = v; + break; + } + } + return (c); +} + +/*)Function int getline() + * + * The function getline() reads a line of input text from a + * .rel source text file, a .lnk command file or from stdin. + * Lines of text are processed from a single .lnk file or + * multiple .rel files until all files have been read. + * The input text line is copied into the global string ib[] + * and converted to a NULL terminated string. The function + * getline() returns a (1) after succesfully reading a line + * or a (0) if all files have been read. + * This function also opens each input .lst file and output + * .rst file as each .rel file is processed. + * + * local variables: + * int i string length + * int ftype file type + * char * fid file name + * + * global variables: + * lfile *cfp The pointer *cfp points to the + * current lfile structure + * lfile *filep The pointer *filep points to the + * beginning of a linked list of + * lfile structures. + * int gline get a line from the LST file + * to translate for the RST file + * char ib[NINPUT] REL file text line + * int pass linker pass number + * int pflag print linker command file flag + * FILE *rfp The file handle to the current + * output RST file + * FILE *sfp The file handle sfp points to the + * currently open file + * FILE * stdin c_library + * FILE * stdout c_library + * FILE *tfp The file handle to the current + * LST file being scanned + * int uflag update listing flag + * + * called functions: + * FILE * afile() lkmain.c + * int fclose() c_library + * char * fgets() c_library + * int fprintf() c_library + * VOID lkulist() lklist.c + * VOID lkexit() lkmain.c + * int strlen() c_library + * + * side effects: + * The input stream is scanned. The .rel files will be + * opened and closed sequentially scanning each in turn. + */ + +int +getline() +{ + register int ftype; + register char *fid; + +loop: if (pflag && cfp && cfp->f_type == F_STD) + fprintf(stdout, "ASlink >> "); + + if (sfp == NULL || fgets(ib, sizeof ib, sfp) == NULL) { + if (sfp) { + fclose(sfp); + sfp = NULL; + lkulist(0); + } + if (cfp == NULL) { + cfp = filep; + } else { + cfp = cfp->f_flp; + } + if (cfp) { + ftype = cfp->f_type; + fid = cfp->f_idp; + if (ftype == F_STD) { + sfp = stdin; + } else + if (ftype == F_LNK) { + sfp = afile(fid, "lnk", 0); + } else + if (ftype == F_REL) { + sfp = afile(fid, "rel", 0); + /* if a .cdb file exists then copy it over */ + if (dflag && sfp && dfp && pass == 0) { + FILE *xfp = afile(fid,"adb",0); //JCF: Nov 30, 2002 + if (xfp) { + copyfile(dfp,xfp); + fclose(xfp); + } + } + if (uflag && pass != 0) { + SaveLinkedFilePath(fid); //Save the linked path for aomf51 + if ((tfp = afile(fid, "lst", 0)) != NULL) { + if ((rfp = afile(fid, "rst", 1)) == NULL) { + fclose(tfp); + tfp = NULL; + } + } + } + gline = 1; + } else { + fprintf(stderr, "Invalid file type\n"); + lkexit(1); + } + if (sfp == NULL) { + lkexit(1); + } + goto loop; + } else { + filep = NULL; + return(0); + } + } + chop_crlf(ib); + return (1); +} + +/*)Function int more() + * + * The function more() scans the input text line + * skipping white space (SPACES and TABS) and returns a (0) + * if the end of the line or a comment delimeter (;) is found, + * or a (1) if their are additional characters in the line. + * + * local variables: + * int c next character from + * the input text line + * + * global variables: + * none + * + * called functions: + * char getnb() lklex.c + * VOID unget() lklex.c + * + * side effects: + * use of getnb() and unget() updates the global pointer ip + * the position in the current input text line + */ + +int +more() +{ + register int c; + + c = getnb(); + unget(c); + return( (c == '\0' || c == ';') ? 0 : 1 ); +} + +/*)Function char endline() + * + * The function endline() scans the input text line + * skipping white space (SPACES and TABS) and returns the next + * character or a (0) if the end of the line is found or a + * comment delimiter (;) is found. + * + * local variables: + * int c next character from + * the input text line + * + * global variables: + * none + * + * called functions: + * char getnb() lklex.c + * + * side effects: + * Use of getnb() updates the global pointer ip the + * position in the current input text line. + */ + +char +endline() +{ + register int c; + + c = getnb(); + return( (c == '\0' || c == ';') ? 0 : c ); +} + +/*)Function VOID chop_crlf(str) + * + * char *str string to chop + * + * The function chop_crlf() removes trailing LF or CR/LF from + * str, if present. + * + * local variables: + * int i string length + * + * global variables: + * none + * + * functions called: + * none + * + * side effects: + * none + */ + +VOID +chop_crlf(str) +char *str; +{ + register int i; + + i = strlen(str); + if (i >= 1 && str[i-1] == '\n') str[i-1] = 0; + if (i >= 2 && str[i-2] == '\r') str[i-2] = 0; +} diff --git a/as/hc08/lklibr.c b/as/hc08/lklibr.c new file mode 100644 index 00000000..8ca45048 --- /dev/null +++ b/as/hc08/lklibr.c @@ -0,0 +1,870 @@ +/* lklibr.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + * + * With contributions for the + * object libraries from + * Ken Hornstein + * kenh@cmf.nrl.navy.mil + * + */ + +#define EQ(A,B) !strcmp((A),(B)) +#define MAXLINE 254 /*when using fgets*/ + +#if defined(__APPLE__) && defined(__MACH__) +#include +#include +#else +#include +#endif +#include +#include +#include +#include "aslink.h" + +/*)Module lklibr.c + * + * The module lklibr.c contains the functions which + * (1) specify the path(s) to library files [.LIB] + * (2) specify the library file(s) [.LIB] to search + * (3) search the library files for specific symbols + * and link the module containing this symbol + * + * lklibr.c contains the following functions: + * VOID addpath() + * VOID addlib() + * VOID addfile() + * VOID search() + * VOID fndsym() + * VOID library() + * VOID loadfile() + * + */ + +/*)Function VOID addpath() + * + * The function addpath() creates a linked structure containing + * the paths to various object module library files. + * + * local variables: + * lbpath *lbph pointer to new path structure + * lbpath *lbp temporary pointer + * + * global variables: + * lbpath *lbphead The pointer to the first + * path structure + * + * functions called: + * char getnb() lklex.c + * VOID * new() lksym.c + * int strlen() c_library + * char * strcpy() c_library + * VOID unget() lklex.c + * + * side effects: + * An lbpath structure may be created. + */ + +VOID +addpath() +{ + struct lbpath *lbph, *lbp; + + lbph = (struct lbpath *) new (sizeof(struct lbpath)); + if (lbphead == NULL) { + lbphead = lbph; + } else { + lbp = lbphead; + while (lbp->next) + lbp = lbp->next; + lbp->next = lbph; + } + unget(getnb()); + lbph->path = (char *) new (strlen(ip)+1); + strcpy(lbph->path, ip); +} + +/*)Function VOID addlib() + * + * The function addlib() tests for the existance of a + * library path structure to determine the method of + * adding this library file to the library search structure. + * + * This function calls the function addfile() to actually + * add the library file to the search list. + * + * local variables: + * lbpath *lbph pointer to path structure + * + * global variables: + * lbpath *lbphead The pointer to the first + * path structure + * ip a pointer to the library name + * + * functions called: + * VOID addfile() lklibr.c + * char getnb() lklex.c + * VOID unget() lklex.c + * + * side effects: + * The function addfile() may add the file to + * the library search list. + */ + +VOID +addlib() +{ + struct lbpath *lbph; + int foundcount=0; + + unget(getnb()); + + if (lbphead == NULL) + { + foundcount=addfile(NULL, ip); + } + else + { + for (lbph=lbphead; lbph; lbph=lbph->next) + { + foundcount+=addfile(lbph->path, ip); + } + } + if(foundcount == 0) + { + printf("?ASlink-Warning-Couldn't find library '%s'\n", ip); + } +} + +/*)Function int addfile(path,libfil) + * + * char *path library path specification + * char *libfil library file specification + * + * The function addfile() searches for the library file + * by concatenating the path and libfil specifications. + * if the library is found, an lbname structure is created + * and linked to any previously defined structures. This + * linked list is used by the function fndsym() to attempt + * to find any undefined symbols. + * + * The function does not give report an error on invalid + * path / file specifications or if the file is not found. + * + * local variables: + * lbname *lbnh pointer to new name structure + * lbname *lbn temporary pointer + * + * global variables: + * lbname *lbnhead The pointer to the first + * path structure + * + * functions called: + * char getnb() lklex.c + * VOID * new() lksym.c + * int strlen() c_library + * char * strcpy() c_library + * VOID unget() lklex.c + * + * side effects: + * An lbname structure may be created. + * + * return: + * 1: the library was found + * 0: the library was not found + */ + +int addfile(char * path, char * libfil) +{ + FILE *fp; + char *str; + struct lbname *lbnh, *lbn; +#ifdef OTHERSYSTEM + int libfilinc=0; +#endif + + if (path != NULL) + { + str = (char *) new (strlen(path) + strlen(libfil) + 6); + strcpy(str,path); +#ifdef OTHERSYSTEM + if (str[strlen(str)-1] != '/') + { + strcat(str,"/"); + } +#endif + } + else + { + str = (char *) new (strlen(libfil) + 5); + } + +#ifdef OTHERSYSTEM + if (libfil[0] == '/') + { + libfil++; + libfilinc=1; + } +#endif + + strcat(str, libfil); + if(strchr(libfil, FSEPX) == NULL) + { + sprintf(&str[strlen(str)], "%clib", FSEPX); + } + + fp=fopen(str, "r"); + if(fp == NULL) + { + /*Ok, that didn't work. Try with the 'libfil' name only*/ +#ifdef OTHERSYSTEM + if(libfilinc) libfil--; +#endif + fp=fopen(libfil, "r"); + if(fp != NULL) + { + /*Bingo! 'libfil' is the absolute path of the library*/ + strcpy(str, libfil); + path=NULL;/*This way 'libfil' and 'path' will be rebuilt from 'str'*/ + } + } + + if(path==NULL) + { + /*'path' can not be null since it is needed to find the '.rel' files associated with + the library. So, get 'path' from 'str' and then chop it off and recreate 'libfil'. + That way putting 'path' and 'libfil' together will result into the original filepath + as contained in 'str'.*/ + int j; + path = (char *) new (strlen(str)); + strcpy(path, str); + for(j=strlen(path)-1; j>=0; j--) + { + if((path[j]=='\\')||(path[j]=='/')) + { + strcpy(libfil, &path[j+1]); + path[j+1]=0; + break; + } + } + if(j<=0) path[0]=0; + } + + if (fp != NULL) + { + fclose(fp); + lbnh = (struct lbname *) new (sizeof(struct lbname)); + if (lbnhead == NULL) + { + lbnhead = lbnh; + } + else + { + lbn = lbnhead; + while (lbn->next) + lbn = lbn->next; + lbn->next = lbnh; + } + + lbnh->path = path; + lbnh->libfil = (char *) new (strlen(libfil) + 1); + strcpy(lbnh->libfil,libfil); + lbnh->libspc = str; + return 1; + } + else + { + free(str); + return 0; + } +} + +/*)Function VOID search() + * + * The function search() looks through all the symbol tables + * at the end of pass 1. If any undefined symbols are found + * then the function fndsym() is called. Function fndsym() + * searches any specified library files to automagically + * import the object modules containing the needed symbol. + * + * After a symbol is found and imported by the function + * fndsym() the symbol tables are again searched. The + * symbol tables are search until no more symbols can be + * resolved within the library files. This ensures that + * back references from one library module to another are + * also resolved. + * + * local variables: + * int i temporary counter + * sym *sp pointer to a symbol structure + * int symfnd found a symbol flag + * + * global variables: + * sym *symhash[] array of pointers to symbol tables + * + * functions called: + * int fndsym() lklibr.c + * + * side effects: + * If a symbol is found then the library object module + * containing the symbol will be imported and linked. + */ + +VOID +search() +{ + register struct sym *sp; + register int i,symfnd; + + /* + * Look for undefined symbols. Keep + * searching until no more symbols are resolved. + */ + symfnd = 1; + while (symfnd) { + symfnd = 0; + /* + * Look through all the symbols + */ + for (i=0; is_type & S_DEF) == 0) { + if (fndsym(sp->s_id)) { + symfnd++; + } + } + sp = sp->s_sp; + } + } + } +} + +/*Load a .rel file embedded in a sdcclib file*/ +void LoadRel(FILE * libfp, char * ModName) +{ + char str[NINPUT+2]; + int state=0; + + while (fgets(str, NINPUT, libfp) != NULL) + { + str[NINPUT+1] = '\0'; + chop_crlf(str); + switch(state) + { + case 0: + if(EQ(str, "")) + { + fgets(str, NINPUT, libfp); + str[NINPUT+1] = '\0'; + chop_crlf(str); + if(EQ(str, ModName)) state=1; + else + { + printf("Bad offset in library file str=%s, Modname=%s\n", str, ModName); + lkexit(1); + } + } + break; + case 1: + if(EQ(str, "")) state=2; + break; + case 2: + if(EQ(str, "")) return; + ip = str; + link_main(); + break; + } + } +} + +/*Load an .adb file embedded in a sdcclib file. If there is +something between and returns 1, otherwise returns 0. +This way the aomf51 will not have uselless empty modules. */ + +int LoadAdb(FILE * libfp) +{ + char str[MAXLINE+1]; + int state=0; + int ToReturn=0; + + while (fgets(str, MAXLINE, libfp) != NULL) + { + str[NINPUT+1] = '\0'; + chop_crlf(str); + switch(state) + { + case 0: + if(EQ(str, "")) state=1; + break; + case 1: + if(EQ(str, "")) return ToReturn; + fprintf(dfp, "%s\n", str); + ToReturn=1; + break; + } + } + return ToReturn; +} + +/*Check for a symbol in a SDCC library. If found, add the embedded .rel and +.adb files from the library. The library must be created with the SDCC +librarian 'sdcclib' since the linking process depends on the correct file offsets +embedded in the library file.*/ + +int SdccLib(char * PathLib, FILE * libfp, char * DirLib, char * SymName) +{ + struct lbfile *lbfh, *lbf; + char ModName[NCPS]=""; + char FLine[MAXLINE+1]; + int state=0; + long IndexOffset=0, FileOffset; + + while(!feof(libfp)) + { + FLine[0]=0; + fgets(FLine, MAXLINE, libfp); + chop_crlf(FLine); + + switch(state) + { + case 0: + if(EQ(FLine, "")) + { + /*The next line has the size of the index*/ + FLine[0]=0; + fgets(FLine, MAXLINE, libfp); + chop_crlf(FLine); + IndexOffset=atol(FLine); + state=1; + } + break; + case 1: + if(EQ(FLine, "")) + { + /*The next line has the name of the module and the offset + of the corresponding embedded file in the library*/ + FLine[0]=0; + fgets(FLine, MAXLINE, libfp); + chop_crlf(FLine); + sscanf(FLine, "%s %ld", ModName, &FileOffset); + state=2; + } + else if(EQ(FLine, "")) + { + /*Reached the end of the index. The symbol is not in this library.*/ + return 0; + } + break; + case 2: + if(EQ(FLine, "")) + { + /*The symbol is not in this module, try the next one*/ + state=1; + } + else + { + /*Check if this is the symbol we are looking for.*/ + if (strncmp(SymName, FLine, NCPS)==0) + { + /*The symbol is in this module.*/ + + /*As in the original library format, it is assumed that the .rel + files reside in the same directory as the lib files.*/ + strcat(DirLib, ModName); + sprintf(&DirLib[strlen(DirLib)], "%crel", FSEPX); + + /*If this module has been loaded already don't load it again.*/ + lbf = lbfhead; + while (lbf) + { + if(EQ(DirLib, lbf->filspc)) return 1;/*Already loaded*/ + lbf=lbf->next; + } + + /*Add the embedded file to the list of files to be loaded in + the second pass. That is performed latter by the function + library() below.*/ + lbfh = (struct lbfile *) new (sizeof(struct lbfile)); + if (lbfhead == NULL) + { + lbfhead = lbfh; + } + else + { + lbf = lbfhead; + while (lbf->next) + lbf = lbf->next; + lbf->next = lbfh; + } + + lbfh->libspc = PathLib; + lbfh->filspc = DirLib; + lbfh->relfil = (char *) new (strlen(ModName) + 1); + strcpy(lbfh->relfil, ModName); + /*Library embedded file, so lbfh->offset must be >=0*/ + lbfh->offset = IndexOffset+FileOffset; + + /*Jump to where the .rel begins and load it.*/ + fseek(libfp, lbfh->offset, SEEK_SET); + LoadRel(libfp, ModName); + + /* if cdb information required & .adb file present */ + if (dflag && dfp) + { + if(LoadAdb(libfp)) + SaveLinkedFilePath(DirLib); + } + return 1; /*Found the symbol, so success!*/ + } + } + break; + + default: + return 0; /*It should never reach this point, but just in case...*/ + break; + } + } + + return 0; /*The symbol is not in this library*/ +} + +/*)Function VOID fndsym(name) + * + * char *name symbol name to find + * + * The function fndsym() searches through all combinations of the + * library path specifications (input by the -k option) and the + * library file specifications (input by the -l option) that + * lead to an existing file. + * + * The file specicifation may be formed in one of two ways: + * + * (1) If the library file contained an absolute + * path/file specification then this becomes filspc. + * (i.e. C:\...) + * + * (2) If the library file contains a relative path/file + * specification then the concatenation of the path + * and this file specification becomes filspc. + * (i.e. \...) + * + * The structure lbfile is created for the first library + * object file which contains the definition for the + * specified undefined symbol. + * + * If the library file [.LIB] contains file specifications for + * non existant files, no errors are returned. + * + * local variables: + * char buf[] [.REL] file input line + * char c [.REL] file input character + * FILE *fp file handle for object file + * lbfile *lbf temporary pointer + * lbfile *lbfh pointer to lbfile structure + * FILE *libfp file handle for library file + * lbname *lbnh pointer to lbname structure + * char *path file specification path + * char relfil[] [.REL] file specification + * char *str combined path and file specification + * char symname[] [.REL] file symbol string + * + * global variables: + * lbname *lbnhead The pointer to the first + * name structure + * lbfile *lbfhead The pointer to the first + * file structure + * + * functions called: + * int fclose() c_library + * int fgets() c_library + * FILE *fopen() c_library + * VOID free() c_library + * char getnb() lklex.c + * VOID lkexit() lkmain.c + * VOID loadfile() lklibr.c + * VOID * new() lksym.c + * char * sprintf() c_library + * int sscanf() c_library + * char * strcat() c_library + * char * strchr() c_library + * char * strcpy() c_library + * int strlen() c_library + * int strncmp() c_library + * VOID unget() lklex.c + * + * side effects: + * If the symbol is found then a new lbfile structure + * is created and added to the linked list of lbfile + * structures. The file containing the found symbol + * is linked. + */ + +int +fndsym(name) +char *name; +{ + FILE *libfp, *fp; + struct lbname *lbnh; + struct lbfile *lbfh, *lbf; + char relfil[NINPUT+2]; + char buf[NINPUT+2]; + char symname[NINPUT]; + char *path,*str; + char c; + int result; + + /* + * Search through every library in the linked list "lbnhead". + */ + + for (lbnh=lbnhead; lbnh; lbnh=lbnh->next) + { + if ((libfp = fopen(lbnh->libspc, "r")) == NULL) + { + fprintf(stderr, "Cannot open library file %s\n", + lbnh->libspc); + lkexit(1); + } + path = lbnh->path; + + /* + * Read in a line from the library file. + * This is the relative file specification + * for a .REL file in this library. + */ + + while (fgets(relfil, NINPUT, libfp) != NULL) + { + relfil[NINPUT+1] = '\0'; + chop_crlf(relfil); + if (path != NULL) + { + str = (char *) new (strlen(path)+strlen(relfil)+6); + strcpy(str,path); +#ifdef OTHERSYSTEM + if (str[strlen(str)-1] != '/') + { + strcat(str,"/"); + } +#endif + } + else + { + str = (char *) new (strlen(relfil) + 5); + } + + if(strcmp(relfil, "")==0) + { + result=SdccLib(lbnh->libspc, libfp, str, name); + fclose(libfp); + if(result) return(1); /*Found the symbol*/ + free(str); + /*The symbol is not in the current library, + check the next library in the list*/ + break; + } + + /*From here down is the support for libraries in the original format*/ + if (relfil[0] == '\\') + { + strcat(str,relfil+1); + } + else + { + strcat(str,relfil); + } + + if(strchr(relfil, FSEPX) == NULL) + { + sprintf(&str[strlen(str)], "%crel", FSEPX); + } + + if ((fp = fopen(str, "r")) != NULL) + { + + /* + * Read in the object file. Look for lines that + * begin with "S" and end with "D". These are + * symbol table definitions. If we find one, see + * if it is our symbol. Make sure we only read in + * our object file and don't go into the next one. + */ + + while (fgets(buf, NINPUT, fp) != NULL) + { + buf[NINPUT+1] = '\0'; + chop_crlf(buf); + /* + * Skip everything that's not a symbol record. + */ + if (buf[0] != 'S') continue; + + /* + * When a 'T line' is found terminate file scan. + * All 'S line's preceed 'T line's in .REL files. + */ + if (buf[0] == 'T') break; + + sscanf(buf, "S %s %c", symname, &c); + + /* + * If we find a symbol definition for the + * symbol we're looking for, load in the + * file and add it to lbfhead so it gets + * loaded on pass number 2. + */ + if (strncmp(symname, name, NCPS) == 0 && c == 'D') + { + lbfh = (struct lbfile *) new (sizeof(struct lbfile)); + if (lbfhead == NULL) + { + lbfhead = lbfh; + } + else + { + lbf = lbfhead; + while (lbf->next) + lbf = lbf->next; + lbf->next = lbfh; + } + + lbfh->libspc = lbnh->libspc; + lbfh->filspc = str; + lbfh->relfil = (char *) new (strlen(relfil) + 1); + lbfh->offset = -1; /*Stand alone rel file*/ + strcpy(lbfh->relfil,relfil); + fclose(fp); + fclose(libfp); + + /* if cdb information required & adb file present */ + if (dflag && dfp) + { + FILE *xfp = afile(str,"adb",0); //JCF: Nov 30, 2002 + if (xfp) + { + SaveLinkedFilePath(str); + copyfile(dfp,xfp); + fclose(xfp); + } + } + loadfile(str); + return (1); + } + } + fclose(fp); + } + free(str); + } + fclose(libfp); + } + return(0); +} + +void loadfile_SdccLib(char * libspc, char * module, long offset) +{ + FILE *fp; + + if ((fp = fopen(libspc,"r")) != NULL) + { + fseek(fp, offset, SEEK_SET); + LoadRel(fp, module); + fclose(fp); + } +} + +/*)Function VOID library() + * + * The function library() links all the library object files + * contained in the lbfile structures. + * + * local variables: + * lbfile *lbfh pointer to lbfile structure + * + * global variables: + * lbfile *lbfhead pointer to first lbfile structure + * + * functions called: + * VOID loadfile lklibr.c + * + * side effects: + * Links all files contained in the lbfile structures. + */ + +VOID +library() +{ + struct lbfile *lbfh; + + for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) + { + if(lbfh->offset<0) + { + /*Stand alone rel file (original lib format)*/ + loadfile(lbfh->filspc); + } + else + { + /*rel file embedded in lib (new lib format)*/ + loadfile_SdccLib(lbfh->libspc, lbfh->relfil, lbfh->offset); + } + } +} + +/*)Function VOID loadfile(filspc) + * + * char *filspc library object file specification + * + * The function loadfile() links the library object module. + * + * local variables: + * FILE *fp file handle + * int i input line length + * char str[] file input line + * + * global variables: + * char *ip pointer to linker input string + * + * functions called: + * int fclose() c_library + * int fgets() c_library + * FILE * fopen() c_library + * VOID link_main() lkmain.c + * int strlen() c_library + * + * side effects: + * If file exists it is linked. + */ + +VOID +loadfile(filspc) +char *filspc; +{ + FILE *fp; + char str[NINPUT+2]; + + if ((fp = fopen(filspc,"r")) != NULL) { + while (fgets(str, NINPUT, fp) != NULL) { + str[NINPUT+1] = '\0'; + chop_crlf(str); + ip = str; + link_main(); + } + fclose(fp); + } +} diff --git a/as/hc08/lklist.c b/as/hc08/lklist.c new file mode 100644 index 00000000..5325ec89 --- /dev/null +++ b/as/hc08/lklist.c @@ -0,0 +1,1099 @@ +/* lklist.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + * + * 28-Oct-97 JLH: + * - lstarea: show s_id as string rather than array [NCPS] + * - lstarea: show a_id as string rather than array [NCPS] + * 31-Oct-97 JLH: add NoICE output file genration in lstarea + * 02-Apr-98 JLH: add XDATA, DATA, BIT flags to area output + */ + +#include +#include +#include +#include "aslink.h" + +/*)Module lklist.c + * + * The module lklist.c contains the functions which + * output the linker .map file and produce a relocated + * listing .rst file. + * + * lklist.c contains the following functions: + * int dgt() + * VOID lstarea() + * VOID lkulist() + * VOID lkalist() + * VOID lkglist() + * VOID newpag() + * VOID slew() + * + * lklist.c contains no local variables. + */ + +/*)Function VOID slew(fp) + * + * FILE * fp output file handle + * + * The function slew() increments the page line counter. + * If the number of lines exceeds the maximum number of + * lines per page then a page skip and a page header are + * output. + * + * local variables: + * int i loop counter + * + * global variables: + * int lop current line number on page + * int xflag Map file radix type flag + * + * functions called: + * int fprintf() c_library + * VOID newpag() lklist.c + * + * side effects: + * The page line and the page count may be updated. + */ + +VOID +slew(fp) +FILE *fp; +{ + register int i; + + if (lop++ >= NLPP) { + newpag(fp); + if (xflag == 0) { + fprintf(fp, "Hexadecimal\n\n"); + } else + if (xflag == 1) { + fprintf(fp, "Octal\n\n"); + } else + if (xflag == 2) { + fprintf(fp, "Decimal\n\n"); + } + fprintf(fp, "Area Addr Size"); + fprintf(fp, " Decimal Bytes (Attributes)\n"); + for(i=0;i<4;++i) + fprintf(fp, " Value--Global"); + fprintf(fp, "\n\n"); + lop += 6; + } +} + +/*)Function VOID newpag() + * + * The function newpag() outputs a page skip, writes the + * first page header line, sets the line count to 1, and + * increments the page counter. + * + * local variables: + * none + * + * global variables: + * int lop current line number on page + * int page current page number + * + * functions called: + * int fprintf() c_library + * + * side effects: + * The page and line counters are updated. + */ + +VOID +newpag(fp) +FILE *fp; +{ + fprintf(fp, "\fASxxxx Linker %s, page %u.\n", VERSION, ++page); + lop = 1; +} + +/* Used for qsort call in lstsym */ +static int _cmpSymByAddr(const void *p1, const void *p2) +{ + struct sym **s1 = (struct sym **)(p1); + struct sym **s2 = (struct sym **)(p2); + int delta = ((*s1)->s_addr + (*s1)->s_axp->a_addr) - + ((*s2)->s_addr + (*s2)->s_axp->a_addr); + + /* Sort first by address, then by name. */ + if (delta) + { + return delta; + } + return strcmp((*s1)->s_id,(*s2)->s_id); +} + + +#if NCPS-8 + +/* NCPS != 8 */ +/*)Function VOID lstarea(xp) + * + * area * xp pointer to an area structure + * + * The function lstarea() creates the linker map output for + * the area specified by pointer xp. The generated output + * area header includes the area name, starting address, + * size of area, number of words (in decimal), and the + * area attributes. The symbols defined in this area are + * sorted by ascending address and output one per line + * in the selected radix. + * + * local variables: + * areax * oxp pointer to an area extension structure + * int c character value + * int i loop counter + * int j bubble sort update status + * char * ptr pointer to an id string + * int nmsym number of symbols in area + * Addr_T a0 temporary + * Addr_T ai temporary + * Addr_T aj temporary + * sym * sp pointer to a symbol structure + * sym ** p pointer to an array of + * pointers to symbol structures + * + * global variables: + * FILE *mfp Map output file handle + * sym *symhash[NHASH] array of pointers to NHASH + * linked symbol lists + * int xflag Map file radix type flag + * + * functions called: + * int fprintf() c_library + * VOID free() c_library + * char * malloc() c_library + * char putc() c_library + * VOID slew() lklist.c + * + * side effects: + * Map output generated. + */ + +VOID +lstarea(xp) +struct area *xp; +{ + register struct areax *oxp; + register int i; + /* int j; */ + register char *ptr; + int nmsym; + /* Addr_T a0; */ + Addr_T ai, aj; + struct sym *sp; + struct sym **p; + int memPage; + + putc('\n', mfp); + if (xflag == 0) { + fprintf(mfp, "Hexadecimal\n\n"); + } else + if (xflag == 1) { + fprintf(mfp, "Octal\n\n"); + } else + if (xflag == 2) { + fprintf(mfp, "Decimal\n\n"); + } + fprintf(mfp, "Area "); + fprintf(mfp, "Addr Size Decimal %s (Attributes)\n", + (xp->a_flag & A_BIT)?"Bits ":"Bytes");/* JCF: For BIT print bits...*/ + fprintf(mfp, "-------------------------------- "); + fprintf(mfp, "---- ---- ------- ----- ------------\n"); + /* + * Output Area Header + */ + ptr = &xp->a_id[0]; + fprintf(mfp, "%-32s", ptr ); /* JLH: width matches --- above */ + ai = xp->a_addr; + aj = xp->a_size; + if (xflag == 0) { + fprintf(mfp, " %04X %04X", ai, aj); + } else + if (xflag == 1) { + fprintf(mfp, " %06o %06o", ai, aj); + } else + if (xflag == 2) { + fprintf(mfp, " %05u %05u", ai, aj); + } + fprintf(mfp, " = %6u. %s ", aj, + (xp->a_flag & A_BIT)?"bits ":"bytes"); /* JCF: For BIT print bits...*/ + if (xp->a_flag & A_ABS) { + fprintf(mfp, "(ABS"); + } else { + fprintf(mfp, "(REL"); + } + if (xp->a_flag & A_OVR) { + fprintf(mfp, ",OVR"); + } else { + fprintf(mfp, ",CON"); + } + if (xp->a_flag & A_PAG) { + fprintf(mfp, ",PAG"); + } + + memPage = 0x00; + if (xp->a_flag & A_CODE) { + fprintf(mfp, ",CODE"); + memPage = 0x0C; + } + if (xp->a_flag & A_XDATA) { + fprintf(mfp, ",XDATA"); + memPage = 0x0D; + } + if (xp->a_flag & A_BIT) { + fprintf(mfp, ",BIT"); + memPage = 0x0B; + } + fprintf(mfp, ")"); + if (xp->a_flag & A_PAG) { + ai = (ai & 0xFF); + aj = (aj > 256); + if (ai || aj) { fprintf(mfp, " "); } + if (ai) { fprintf(mfp, " Boundary"); } + if (ai & aj) { fprintf(mfp, " /"); } + if (aj) { fprintf(mfp, " Length"); } + if (ai || aj) { fprintf(mfp, " Error"); } + } + + /* + * Find number of symbols in area + */ + nmsym = 0; + oxp = xp->a_axp; + while (oxp) { + for (i=0; is_axp) + ++nmsym; + sp = sp->s_sp; + } + } + oxp = oxp->a_axp; + } + if (nmsym == 0) { + putc('\n', mfp); + return; + } + + /* + * Allocate space for an array of pointers to symbols + * and load array. + */ + if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *))) + == NULL) { + fprintf(mfp, "\nInsufficient space to build Map Segment.\n"); + return; + } + nmsym = 0; + oxp = xp->a_axp; + while (oxp) { + for (i=0; is_axp) { + p[nmsym++] = sp; + } + sp = sp->s_sp; + } + } + oxp = oxp->a_axp; + } + +#if 0 + /* + * Bubble Sort of Addresses in Symbol Table Array + */ + j = 1; + while (j) { + j = 0; + sp = p[0]; + a0 = sp->s_addr + sp->s_axp->a_addr; + for (i=1; is_addr + sp->s_axp->a_addr; + if (a0 > ai) { + j = 1; + p[i] = p[i-1]; + p[i-1] = sp; + } + a0 = ai; + } + } +#else + qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr); +#endif + + /* + * Symbol Table Output + */ + + i = 0; + fprintf(mfp, "\n\n"); + fprintf(mfp, " Value Global\n"); + fprintf(mfp, " -------- --------------------------------"); + while (i < nmsym) { + fprintf(mfp, "\n"); + if (memPage != 0) + fprintf(mfp, " %02X:", memPage); + else + fprintf(mfp, " "); + + sp = p[i]; + aj = sp->s_addr + sp->s_axp->a_addr; + if (xflag == 0) { + fprintf(mfp, "%04X ", aj); + } else + if (xflag == 1) { + fprintf(mfp, "%06o ", aj); + } else + if (xflag == 2) { + fprintf(mfp, "%05u ", aj); + } + ptr = &sp->s_id[0]; + fprintf(mfp, "%s", ptr ); + + /* if cdb flag set the output cdb Information + and the symbol has a '$' sign in it then */ + if (dflag && + strchr(ptr,'$')) + fprintf(dfp,"L:%s:%X\n",ptr,aj); + + /* NoICE output of symbol */ + if (jflag) DefineNoICE( ptr, aj, memPage ); + + i++; + } + putc('\n', mfp); + free(p); +} + +#else + +/* NCPS == 8 */ +/*)Function VOID lstarea(xp) + * + * area * xp pointer to an area structure + * + * The function lstarea() creates the linker map output for + * the area specified by pointer xp. The generated output + * area header includes the area name, starting address, + * size of area, number of words (in decimal), and the + * area attributes. The symbols defined in this area are + * sorted by ascending address and output four per line + * in the selected radix. + * + * local variables: + * areax * oxp pointer to an area extension structure + * int c character value + * int i loop counter + * int j bubble sort update status + * char * ptr pointer to an id string + * int nmsym number of symbols in area + * Addr_T a0 temporary + * Addr_T ai temporary + * Addr_T aj temporary + * sym * sp pointer to a symbol structure + * sym ** p pointer to an array of + * pointers to symbol structures + * + * global variables: + * FILE *mfp Map output file handle + * sym *symhash[NHASH] array of pointers to NHASH + * linked symbol lists + * int xflag Map file radix type flag + * + * functions called: + * int fprintf() c_library + * VOID free() c_library + * char * malloc() c_library + * char putc() c_library + * VOID slew() lklist.c + * + * side effects: + * Map output generated. + */ + +VOID +lstarea(xp) +struct area *xp; +{ + register struct areax *oxp; + register c, i, j; + register char *ptr; + int nmsym; + Addr_T a0, ai, aj; + struct sym *sp; + struct sym **p; + int page; + + putc('\n', mfp); + slew(mfp); + /* + * Output Area Header + */ + ptr = &xp->a_id[0]; + while (ptr < &xp->a_id[NCPS]) { + if ((c = *ptr++) != 0) { + putc(c, mfp); + } else { + putc(' ', mfp); + } + } + ai = xp->a_addr; + aj = xp->a_size; + if (xflag == 0) { + fprintf(mfp, " %04X %04X", ai, aj); + } else + if (xflag == 1) { + fprintf(mfp, " %06o %06o", ai, aj); + } else + if (xflag == 2) { + fprintf(mfp, " %05u %05u", ai, aj); + } + fprintf(mfp, " = %6u. bytes ", aj); + if (xp->a_flag & A_ABS) { + fprintf(mfp, "(ABS"); + } else { + fprintf(mfp, "(REL"); + } + if (xp->a_flag & A_OVR) { + fprintf(mfp, ",OVR"); + } else { + fprintf(mfp, ",CON"); + } + if (xp->a_flag & A_PAG) { + fprintf(mfp, ",PAG"); + } + + page = 0x00; + if (xp->a_flag & A_CODE) { + fprintf(mfp, ",CODE"); + memPage = 0x0C; + } + if (xp->a_flag & A_XDATA) { + fprintf(mfp, ",XDATA"); + memPage = 0x0D; + } + if (xp->a_flag & A_BIT) { + fprintf(mfp, ",BIT"); + memPage = 0x0B; + } + fprintf(mfp, ")"); + if (xp->a_flag & A_PAG) { + ai = (ai & 0xFF); + aj = (aj > 256); + if (ai || aj) { fprintf(mfp, " "); } + if (ai) { fprintf(mfp, " Boundary"); } + if (ai & aj) { fprintf(mfp, " /"); } + if (aj) { fprintf(mfp, " Length"); } + if (ai || aj) { fprintf(mfp, " Error"); } + } + + /* + * Find number of symbols in area + */ + nmsym = 0; + oxp = xp->a_axp; + while (oxp) { + for (i=0; is_axp) + ++nmsym; + sp = sp->s_sp; + } + } + oxp = oxp->a_axp; + } + if (nmsym == 0) { + putc('\n', mfp); + slew(mfp); + return; + } + + /* + * Allocate space for an array of pointers to symbols + * and load array. + */ + if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *))) + == NULL) { + fprintf(mfp, "\nInsufficient space to build Map Segment.\n"); + slew(mfp); + return; + } + nmsym = 0; + oxp = xp->a_axp; + while (oxp) { + for (i=0; is_axp) { + p[nmsym++] = sp; + } + sp = sp->s_sp; + } + } + oxp = oxp->a_axp; + } + +#if 0 + /* + * Bubble Sort of Addresses in Symbol Table Array + */ + j = 1; + while (j) { + j = 0; + sp = p[0]; + a0 = sp->s_addr + sp->s_axp->a_addr; + for (i=1; is_addr + sp->s_axp->a_addr; + if (a0 > ai) { + j = 1; + p[i] = p[i-1]; + p[i-1] = sp; + } + a0 = ai; + } + } +#else + qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr); +#endif + + /* + * Symbol Table Output + */ + i = 0; + while (i < nmsym) { + fprintf(mfp, "\n"); + slew(mfp); + fprintf(mfp, " "); + sp = p[i]; + aj = sp->s_addr + sp->s_axp->a_addr; + if (xflag == 0) { + fprintf(mfp, " %04X ", aj); + } else + if (xflag == 1) { + fprintf(mfp, "%06o ", aj); + } else + if (xflag == 2) { + fprintf(mfp, " %05u ", aj); + } + ptr = &sp->s_id[0]; + fprintf(mfp, "%s", ptr ); + + /* NoICE output of symbol */ + if (jflag) DefineNoICE( ptr, aj, memPage ); + } + putc('\n', mfp); + free(p); + slew(mfp); +} +#endif + +/*)Function VOID lkulist(i) + * + * int i i # 0 process LST to RST file + * i = 0 copy remainder of LST file + * to RST file and close files + * + * The function lkulist() creates a relocated listing (.rst) + * output file from the ASxxxx assembler listing (.lst) + * files. The .lst file's program address and code bytes + * are changed to reflect the changes made by ASlink as + * the .rel files are combined into a single relocated + * output file. + * + * local variables: + * Addr_T pc current program counter address + * + * global variables: + * int hilo byte order + * int gline get a line from the LST file + * to translate for the RST file + * char rb[] read listing file text line + * FILE *rfp The file handle to the current + * output RST file + * int rtcnt count of data words + * int rtflg[] output the data flag + * Addr_T rtval[] relocated data + * FILE *tfp The file handle to the current + * LST file being scanned + * + * functions called: + * int fclose() c_library + * int fgets() c_library + * int fprintf() c_library + * VOID lkalist() lklist.c + * VOID lkglist() lklist.c + * + * side effects: + * A .rst file is created for each available .lst + * file associated with a .rel file. + */ + +VOID +lkulist(i) +int i; +{ + Addr_T pc; + + /* + * Exit if listing file is not open + */ + if (tfp == NULL) + return; + + /* + * Normal processing of LST to RST + */ + if (i) { + /* + * Evaluate current code address + */ + if (hilo == 0) { + pc = ((rtval[1] & 0xFF) << 8) + (rtval[0] & 0xFF); + } else { + pc = ((rtval[0] & 0xFF) << 8) + (rtval[1] & 0xFF); + } + + /* + * Line with only address + */ + if (rtcnt == 2) { + lkalist(pc); + + /* + * Line with address and code + */ + } else { + for (i=2; i < rtcnt; i++) { + if (rtflg[i]) { + lkglist(pc++, rtval[i] & 0xFF); + } + } + } + + /* + * Copy remainder of LST to RST + */ + } else { + if (gline == 0) + fprintf(rfp, "%s", rb); + + while (fgets(rb, sizeof(rb), tfp) != 0) { + fprintf(rfp, "%s", rb); + } + fclose(tfp); + tfp = NULL; + fclose(rfp); + rfp = NULL; + } +} + +/*)Function VOID lkalist(pc) + * + * int pc current program counter value + * + * The function lkalist() performs the following functions: + * + * (1) if the value of gline = 0 then the current listing + * file line is copied to the relocated listing file output. + * + * (2) the listing file is read line by line and copied to + * the relocated listing file until a valid source + * line number and a program counter value of the correct + * radix is found. The new relocated pc value is substituted + * and the line is written to the RST file. + * + * local variables: + * int i loop counter + * char str[] temporary string + * + * global variables: + * int gcntr data byte counter + * int gline get a line from the LST file + * to translate for the RST file + * char rb[] read listing file text line + * char *rp pointer to listing file text line + * FILE *rfp The file handle to the current + * output RST file + * FILE *tfp The file handle to the current + * LST file being scanned + * + * functions called: + * int dgt() lklist.c + * int fclose() c_library + * int fgets() c_library + * int fprintf() c_library + * int sprintf() c_library + * char * strncpy() c_library + * + * side effects: + * Lines of the LST file are copied to the RST file, + * the last line copied has the code address + * updated to reflect the program relocation. + */ + +VOID +lkalist(pc) +Addr_T pc; +{ + char str[8]; + int i; + + /* + * Exit if listing file is not open + */ +loop: if (tfp == NULL) + return; + + /* + * Copy current LST to RST + */ + if (gline == 0) { + fprintf(rfp, "%s", rb); + gline = 1; + } + + /* + * Clear text line buffer + */ + for (i=0,rp=rb; i +#include +#include +#include "aslink.h" + +#ifdef WIN32T +#include + +void Timer(int action, char * message) +{ + static double start, end, total=0.0; + static const double secs_per_tick = 1.0 / CLOCKS_PER_SEC; + + if(action==0) start=clock()*secs_per_tick; + else if(action==1) + { + end=clock() * secs_per_tick; + printf("%s \t%f seconds.\n", message, (end-start)); + total+=end-start; + } + else + { + printf("Total time: \t%f seconds.\n", total); + total=0.0; + } +} +#endif + +/* yuck - but including unistd.h causes problems on Cygwin by redefining + * Addr_T. + */ +extern int unlink(const char *); + +/*)Module lkmain.c + * + * The module lkmain.c contains the functions which + * (1) input the linker options, parameters, and specifications + * (2) perform a two pass link + * (3) produce the appropriate linked data output and/or + * link map file and/or relocated listing files. + * + * lkmain.c contains the following functions: + * FILE * afile(fn,ft,wf) + * VOID bassav() + * VOID gblsav() + * VOID link_main() + * VOID lkexit() + * VOID main(argc,argv) + * VOID map() + * int parse() + * VOID setbas() + * VOID setgbl() + * VOID usage() + * + * lkmain.c contains the following local variables: + * char * usetext[] array of pointers to the + * command option tect lines + * + */ + +/*JCF: Creates some of the default areas so they are allocated in the right order.*/ +void Areas51 (void) +{ + char * rel[]={ + "XH", + "H 7 areas 0 global symbols", + "A _CODE size 0 flags 0", /*Each .rel has one, so...*/ + "A REG_BANK_0 size 0 flags 4", /*Register banks are overlayable*/ + "A REG_BANK_1 size 0 flags 4", + "A REG_BANK_2 size 0 flags 4", + "A REG_BANK_3 size 0 flags 4", + "A BSEG size 0 flags 80", /*BSEG must be just before BITS*/ + "A BSEG_BYTES size 0 flags 0", /*Size will be obtained from BSEG in lnkarea()*/ + "" + }; + int j; + + for (j=0; rel[j][0]!=0; j++) + { + ip=rel[j]; + link_main(); + } + + /*Set the start address of the default areas:*/ + for(ap=areap; ap; ap=ap->a_ap) + { + /**/ if (!strcmp(ap->a_id, "REG_BANK_0")) { ap->a_addr=0x00; ap->a_type=1; } + else if (!strcmp(ap->a_id, "REG_BANK_1")) { ap->a_addr=0x08; ap->a_type=1; } + else if (!strcmp(ap->a_id, "REG_BANK_2")) { ap->a_addr=0x10; ap->a_type=1; } + else if (!strcmp(ap->a_id, "REG_BANK_3")) { ap->a_addr=0x18; ap->a_type=1; } + else if (!strcmp(ap->a_id, "BSEG_BYTES")) { ap->a_addr=0x20; ap->a_type=1; } + } +} + +/*)Function VOID main(argc,argv) + * + * int argc number of command line arguments + 1 + * char * argv[] array of pointers to the command line + * arguments + * + * The function main() evaluates the command line arguments to + * determine if the linker parameters are to input through 'stdin' + * or read from a command file. The functiond getline() and parse() + * are to input and evaluate the linker parameters. The linking process + * proceeds by making the first pass through each .rel file in the order + * presented to the linker. At the end of the first pass the setbase(), + * lnkarea(), setgbl(), and symdef() functions are called to evaluate + * the base address terms, link all areas, define global variables, + * and look for undefined symbols. Following these routines a linker + * map file may be produced and the linker output files may be opened. + * The second pass through the .rel files will output the linked data + * in one of the four supported formats. + * + * local variables: + * char * p pointer to an argument string + * int c character from argument string + * int i loop counter + * + * global variables: + * text line in ib[] + * lfile *cfp The pointer *cfp points to the + * current lfile structure + * char ctype[] array of character types, one per + * ASCII character + * lfile *filep The pointer *filep points to the + * beginning of a linked list of + * lfile structures. + * head *hp Pointer to the current + * head structure + * char ib[NINPUT] .rel file text line + * char *ip pointer into the .rel file + * lfile *linkp pointer to first lfile structure + * containing an input .rel file + * specification + * int lkerr error flag + * int mflag Map output flag + * int oflag Output file type flag + * FILE *ofp Output file handle + * for word formats + * FILE *ofph Output file handle + * for high byte format + * FILE *ofpl Output file handle + * for low byte format + * int pass linker pass number + * int pflag print linker command file flag + * int radix current number conversion radix + * FILE *sfp The file handle sfp points to the + * currently open file + * lfile *startp asmlnk startup file structure + * FILE * stdin c_library + * FILE * stdout c_library + * + * functions called: + * FILE * afile() lkmain.c + * int fclose() c_library + * int fprintf() c_library + * int getline() lklex.c + * VOID library() lklibr.c + * VOID link_main() lkmain.c + * VOID lkexit() lkmain.c + * VOID lnkarea() lkarea.c + * VOID map() lkmain.c + * VOID new() lksym.c + * int parse() lkmain.c + * VOID reloc() lkreloc.c + * VOID search() lklibr.c + * VOID setbas() lkmain.c + * VOID setgbl() lkmain.c + * VOID symdef() lksym.c + * VOID usage() lkmain.c + * + * side effects: + * Completion of main() completes the linking process + * and may produce a map file (.map) and/or a linked + * data files (.ihx or .s19) and/or one or more + * relocated listing files (.rst). + */ + +int +main(argc, argv) +char *argv[]; +{ + register char *p; + register int c, i; + +#ifdef WIN32T + Timer(0, ""); +#endif + + startp = (struct lfile *) new (sizeof (struct lfile)); + + pflag = 1; + for (i=1; if_type = F_STD; + break; + + case 'f': + case 'F': + startp->f_type = F_LNK; + break; + + case 'n': + case 'N': + pflag = 0; + break; + + case 'p': + case 'P': + pflag = 1; + break; + + default: + usage(); + } + } + } else { + if (startp->f_type == F_LNK) { + startp->f_idp = p; + } + } + } + if (startp->f_type == 0) + usage(); + if (startp->f_type == F_LNK && startp->f_idp == NULL) + usage(); + + cfp = NULL; + sfp = NULL; + filep = startp; + while (1) { + ip = ib; + if (getline() == 0) + break; + if (pflag && sfp != stdin) + fprintf(stdout, "%s\n", ip); + if (*ip == '\0' || parse()) + break; + } + + if (sfp) { + fclose(sfp); + sfp = NULL; + } + + if (linkp == NULL) + usage(); + + syminit(); + + if (dflag){ + //dfp = afile("temp", "cdb", 1); + SaveLinkedFilePath(linkp->f_idp); //Must be the first one... + dfp = afile(linkp->f_idp,"cdb",1); //JCF: Nov 30, 2002 + if (dfp == NULL) + lkexit(1); + } + + for (pass=0; pass<2; ++pass) { + cfp = NULL; + sfp = NULL; + filep = linkp; + hp = NULL; + radix = 10; + + Areas51(); /*JCF: Create the default 8051 areas in the right order*/ + + while (getline()) { + ip = ib; + + /* pass any "magic comments" to NoICE output */ + if ((ip[0] == ';') && (ip[1] == '!') && jfp) { + fprintf( jfp, "%s\n", &ip[2] ); + } + link_main(); + } + if (pass == 0) { + /* + * Search libraries for global symbols + */ + search(); + /* + * Set area base addresses. + */ + setbas(); + /* + * Link all area addresses. + */ + lnkarea(); + /* + * Process global definitions. + */ + setgbl(); + /* + * Check for undefined globals. + */ + symdef(stderr); + + /* Open NoICE output file if requested */ + if (jflag) { + jfp = afile(linkp->f_idp, "NOI", 1); + if (jfp == NULL) { + lkexit(1); + } + } + + /* + * Output Link Map if requested, + * or if NoICE output requested (since NoICE + * file is generated in part by map() processing) + */ + if (mflag || jflag) + map(); + + if (sflag) /*JCF: memory usage summary output*/ + if(summary(areap))lkexit(1); + + if (iram_size) + iramcheck(); + + /* + * Open output file + */ + if (oflag == 1) { + ofp = afile(linkp->f_idp, "ihx", 1); + if (ofp == NULL) { + lkexit(1); + } + /* include NoICE command to load hex file */ + if (jfp) fprintf( jfp, "LOAD %s.IHX\n", linkp->f_idp ); + + } else + if (oflag == 2) { + ofp = afile(linkp->f_idp, "S19", 1); + if (ofp == NULL) { + lkexit(1); + } + /* include NoICE command to load hex file */ + if (jfp) fprintf( jfp, "LOAD %s.S19\n", linkp->f_idp ); + } + } else { + /* + * Link in library files + */ + library(); + reloc('E'); + } + } + //JCF: + CreateAOMF51(); + +#ifdef WIN32T + Timer(1, "Linker execution time"); +#endif + + lkexit(lkerr); + return 0; +} + +/*)Function VOID lkexit(i) + * + * int i exit code + * + * The function lkexit() explicitly closes all open + * files and then terminates the program. + * + * local variables: + * none + * + * global variables: + * FILE * mfp file handle for .map + * FILE * ofp file handle for .ihx/.s19 + * FILE * rfp file hanlde for .rst + * FILE * sfp file handle for .rel + * FILE * tfp file handle for .lst + * + * functions called: + * int fclose() c_library + * VOID exit() c_library + * + * side effects: + * All files closed. Program terminates. + */ + +VOID +lkexit(i) +int i; +{ + if (mfp != NULL) fclose(mfp); + if (jfp != NULL) fclose(jfp); + if (ofp != NULL) fclose(ofp); + if (rfp != NULL) fclose(rfp); + if (sfp != NULL) fclose(sfp); + if (tfp != NULL) fclose(tfp); + if (dfp != NULL) fclose(dfp); + /*if (dfp != NULL) + FILE *xfp = afile(linkp->f_idp,"cdb",1); + dfp = freopen("temp.cdb","r",dfp); + copyfile(xfp,dfp); + fclose(xfp); + fclose(dfp); + unlink("temp.cdb"); + }*/ + exit(i); +} + +/*)Function link_main() + * + * The function link_main() evaluates the directives for each line of + * text read from the .rel file(s). The valid directives processed + * are: + * X, D, Q, H, M, A, S, T, R, and P. + * + * local variables: + * int c first non blank character of a line + * + * global variables: + * head *headp The pointer to the first + * head structure of a linked list + * head *hp Pointer to the current + * head structure + * int pass linker pass number + * int radix current number conversion radix + * + * functions called: + * char endline() lklex.c + * VOID module() lkhead.c + * VOID newarea() lkarea.c + * VOID newhead() lkhead.c + * sym * newsym() lksym.c + * VOID reloc() lkreloc.c + * + * side effects: + * Head, area, and symbol structures are created and + * the radix is set as the .rel file(s) are read. + */ + +VOID +link_main() +{ + register int c; + + if ((c=endline()) == 0) { return; } + switch (c) { + + case 'O': /*For some important sdcc options*/ + if (pass == 0) + { + if(strlen(sdccopt)==0) + { + strcpy(sdccopt, &ip[1]); + strcpy(sdccopt_module, curr_module); + } + else + { + if(strcmp(sdccopt, &ip[1])!=0) + { + fprintf(stderr, + "?ASlink-Warning-Conflicting sdcc options:\n" + " \"%s\" in module \"%s\" and\n" + " \"%s\" in module \"%s\".\n", + sdccopt, sdccopt_module, &ip[1], curr_module); + lkerr++; + } + } + } + break; + + case 'X': + radix = 16; + break; + + case 'D': + radix = 10; + break; + + case 'Q': + radix = 8; + break; + + case 'H': + if (pass == 0) { + newhead(); + } else { + if (hp == 0) { + hp = headp; + } else { + hp = hp->h_hp; + } + } + sdp.s_area = NULL; + sdp.s_areax = NULL; + sdp.s_addr = 0; + break; + + case 'M': + if (pass == 0) + { + strcpy(curr_module, &ip[1]); + module(); + } + break; + + case 'A': + if (pass == 0) + newarea(); + if (sdp.s_area == NULL) { + sdp.s_area = areap; + sdp.s_areax = areap->a_axp; + sdp.s_addr = 0; + } + break; + + case 'S': + if (pass == 0) + newsym(); + break; + + case 'T': + case 'R': + case 'P': + if (pass == 0) + break; + reloc(c); + break; + + default: + break; + } + if (c == 'X' || c == 'D' || c == 'Q') { + if ((c = get()) == 'H') { + hilo = 1; + } else + if (c == 'L') { + hilo = 0; + } + } +} + + +/*)Function VOID map() + * + * The function map() opens the output map file and calls the various + * routines to + * (1) output the variables in each area, + * (2) list the files processed with module names, + * (3) list the libraries file processed, + * (4) list base address definitions, + * (5) list global variable definitions, and + * (6) list any undefined variables. + * + * local variables: + * int i counter + * head * hdp pointer to head structure + * lbfile *lbfh pointer to library file structure + * + * 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 + * lfile *filep The pointer *filep points to the + * beginning of a linked list of + * lfile structures. + * globl *globlp The pointer to the first + * globl structure + * globl *gsp Pointer to the current + * globl structure + * head *headp The pointer to the first + * head structure of a linked list + * lbfile *lbfhead The pointer to the first + * lbfile structure of a linked list + * lfile *linkp pointer to first lfile structure + * containing an input REL file + * specification + * int lop current line number on page + * FILE *mfp Map output file handle + * int page current page number + * + * functions called: + * FILE * afile() lkmain.c + * int fprintf() c_library + * VOID lkexit() lkmain.c + * VOID lstarea() lklist.c + * VOID newpag() lklist.c + * VOID symdef() lksym.c + * + * side effects: + * The map file is created. + */ + +VOID +map() +{ + register int i; + register struct head *hdp; + register struct lbfile *lbfh; + + /* + * Open Map File + */ + mfp = afile(linkp->f_idp, "map", 1); + if (mfp == NULL) { + lkexit(1); + } + + /* + * Output Map Area Lists + */ + page = 0; + lop = NLPP; + ap = areap; + while (ap) { + lstarea(ap); + ap = ap->a_ap; + } + /* + * List Linked Files + */ + newpag(mfp); + fprintf(mfp, "\nFiles Linked [ module(s) ]\n\n"); + hdp = headp; + filep = linkp; + while (filep) { + fprintf(mfp, "%-16s", filep->f_idp); + i = 0; + while ((hdp != NULL) && (hdp->h_lfile == filep)) { + if (i % 5) { + fprintf(mfp, ", %8.8s", hdp->m_id); + } else { + if (i) { + fprintf(mfp, ",\n%20s%8.8s", "", hdp->m_id); + } else { + fprintf(mfp, " [ %8.8s", hdp->m_id); + } + } + hdp = hdp->h_hp; + i++; + } + if (i) + fprintf(mfp, " ]"); + fprintf(mfp, "\n"); + filep = filep->f_flp; + } + /* + * List Linked Libraries + */ + if (lbfhead != NULL) { + fprintf(mfp, + "\nLibraries Linked [ object file ]\n\n"); + for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) { + fprintf(mfp, "%-32s [ %16.16s ]\n", + lbfh->libspc, lbfh->relfil); + } + fprintf(mfp, "\n"); + } + /* + * List Base Address Definitions + */ + if (basep) { + newpag(mfp); + fprintf(mfp, "\nUser Base Address Definitions\n\n"); + bsp = basep; + while (bsp) { + fprintf(mfp, "%s\n", bsp->b_strp); + bsp = bsp->b_base; + } + } + /* + * List Global Definitions + */ + if (globlp) { + newpag(mfp); + fprintf(mfp, "\nUser Global Definitions\n\n"); + gsp = globlp; + while (gsp) { + fprintf(mfp, "%s\n", gsp->g_strp); + gsp = gsp->g_globl; + } + } + fprintf(mfp, "\n\f"); + symdef(mfp); +} + +/*)Function int parse() + * + * The function parse() evaluates all command line or file input + * linker directives and updates the appropriate variables. + * + * local variables: + * int c character value + * char fid[] file id string + * + * global variables: + * char ctype[] array of character types, one per + * ASCII character + * lfile *lfp pointer to current lfile structure + * being processed by parse() + * lfile *linkp pointer to first lfile structure + * containing an input REL file + * specification + * int mflag Map output flag + * int oflag Output file type flag + * int pflag print linker command file flag + * FILE * stderr c_library + * int uflag Relocated listing flag + * int xflag Map file radix type flag + * + * Functions called: + * VOID addlib() lklibr.c + * VOID addpath() lklibr.c + * VOID bassav() lkmain.c + * int fprintf() c_library + * VOID gblsav() lkmain.c + * VOID getfid() lklex.c + * char getnb() lklex.c + * VOID lkexit() lkmain.c + * char * strcpy() c_library + * int strlen() c_library + * + * side effects: + * Various linker flags are updated and the linked + * structure lfile is created. + */ + +int +parse() +{ + register int c; + char fid[NINPUT]; + + while ((c = getnb()) != 0) { + if ( c == '-') { + while (ctype[c=get()] & LETTER) { + switch(c) { + + case 'i': + case 'I': + oflag = 1; + break; + + case 's': + case 'S': + oflag = 2; + break; + + case 'm': + case 'M': + ++mflag; + break; + + case 'y': /*JCF: memory usage summary output*/ + case 'Y': + ++sflag; + break; + + case 'j': + case 'J': + jflag = 1; + break; + + case 'u': + case 'U': + uflag = 1; + break; + case 'r': + case 'R': + rflag = 1; + break; + case 'x': + case 'X': + xflag = 0; + break; + + case 'q': + case 'Q': + xflag = 1; + break; + + case 'd': + case 'D': + xflag = 2; + break; + + case 'e': + case 'E': + return(1); + + case 'n': + case 'N': + pflag = 0; + break; + + case 'p': + case 'P': + pflag = 1; + break; + + case 'b': + case 'B': + bassav(); + return(0); + + case 'g': + case 'G': + gblsav(); + return(0); + + case 'k': + case 'K': + addpath(); + return(0); + + case 'l': + case 'L': + addlib(); + return(0); + + case 'a': + case 'A': + iramsav(); + return(0); + + case 'v': + case 'V': + xramsav(); + return(0); + + case 'w': + case 'W': + codesav(); + return(0); + + case 'z': + case 'Z': + dflag = 1; + return(0); + default: + fprintf(stderr, "Invalid option\n"); + lkexit(1); + } + } + } else + if (ctype[c] & ILL) { + fprintf(stderr, "Invalid input"); + lkexit(1); + } else { + if (linkp == NULL) { + linkp = (struct lfile *) + new (sizeof (struct lfile)); + lfp = linkp; + } else { + lfp->f_flp = (struct lfile *) + new (sizeof (struct lfile)); + lfp = lfp->f_flp; + } + getfid(fid, c); + lfp->f_idp = (char *) new (strlen(fid)+1); + strcpy(lfp->f_idp, fid); + lfp->f_type = F_REL; + } + } + return(0); +} + +/*)Function VOID bassav() + * + * The function bassav() creates a linked structure containing + * the base address strings input to the linker. + * + * local variables: + * none + * + * global variables: + * 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[] + * + * functions called: + * char getnb() lklex.c + * VOID * new() lksym.c + * int strlen() c_library + * char * strcpy() c_library + * VOID unget() lklex.c + * + * side effects: + * The basep structure is created. + */ + +VOID +bassav() +{ + if (basep == NULL) { + basep = (struct base *) + new (sizeof (struct base)); + bsp = basep; + } else { + bsp->b_base = (struct base *) + new (sizeof (struct base)); + bsp = bsp->b_base; + } + unget(getnb()); + bsp->b_strp = (char *) new (strlen(ip)+1); + strcpy(bsp->b_strp, ip); +} + +/*)Function VOID setbas() + * + * The function setbas() scans the base address lines in hte + * basep structure, evaluates the arguments, and sets beginning + * address of the specified areas. + * + * local variables: + * int 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: + * Addr_T expr() lkeval.c + * int fprintf() c_library + * VOID getid() lklex.c + * char getnb() lklex.c + * int symeq() lksym.c + * + * side effects: + * The base address of an area is set. + */ + +VOID +setbas() +{ + register int 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)) + break; + } + if (ap == NULL) { + fprintf(stderr, + "ASlink-Warning-No definition of area %s\n", id); + lkerr++; + } else { + ap->a_addr = v; + ap->a_type = 1; /* JLH: value set */ + } + } else { + fprintf(stderr, "ASlink-Warning-No '=' in base expression"); + lkerr++; + } + bsp = bsp->b_base; + } +} + +/*)Function VOID gblsav() + * + * The function gblsav() creates a linked structure containing + * the global variable strings input to the linker. + * + * local variable: + * none + * + * global variables: + * globl *globlp The pointer to the first + * globl structure + * globl *gsp Pointer to the current + * globl structure + * char *ip pointer into the REL file + * text line in ib[] + * int lkerr error flag + * + * functions called: + * char getnb() lklex.c + * VOID * new() lksym.c + * int strlen() c_library + * char * strcpy() c_library + * VOID unget() lklex.c + * + * side effects: + * The globlp structure is created. + */ + +VOID +gblsav() +{ + if (globlp == NULL) { + globlp = (struct globl *) + new (sizeof (struct globl)); + gsp = globlp; + } else { + gsp->g_globl = (struct globl *) + new (sizeof (struct globl)); + gsp = gsp->g_globl; + } + unget(getnb()); + gsp->g_strp = (char *) new (strlen(ip)+1); + strcpy(gsp->g_strp, ip); +} + +/*)Function VOID setgbl() + * + * The function setgbl() scans the global variable lines in hte + * globlp structure, evaluates the arguments, and sets a variable + * to this value. + * + * local variables: + * int v expression value + * char id[] base id string + * sym * sp pointer to a symbol structure + * + * global variables: + * char *ip pointer into the REL file + * text line in ib[] + * globl *globlp The pointer to the first + * globl structure + * globl *gsp Pointer to the current + * globl structure + * FILE * stderr c_library + * int lkerr error flag + * + * functions called: + * Addr_T expr() lkeval.c + * int fprintf() c_library + * VOID getid() lklex.c + * char getnb() lklex.c + * sym * lkpsym() lksym.c + * + * side effects: + * The value of a variable is set. + */ + +VOID +setgbl() +{ + register int v; + register struct sym *sp; + char id[NCPS]; + + gsp = globlp; + while (gsp) { + ip = gsp->g_strp; + getid(id, -1); + if (getnb() == '=') { + v = expr(0); + sp = lkpsym(id, 0); + if (sp == NULL) { + fprintf(stderr, + "No definition of symbol %s\n", id); + lkerr++; + } else { + if (sp->s_flag & S_DEF) { + fprintf(stderr, + "Redefinition of symbol %s\n", id); + lkerr++; + sp->s_axp = NULL; + } + sp->s_addr = v; + sp->s_type |= S_DEF; + } + } else { + fprintf(stderr, "No '=' in global expression"); + lkerr++; + } + gsp = gsp->g_globl; + } +} + +/*)Function FILE * afile(fn,, ft, wf) + * + * char * fn file specification string + * char * ft file type string + * int wf read(0)/write(1) flag + * + * The function afile() opens a file for reading or writing. + * (1) If the file type specification string ft + * is not NULL then a file specification is + * constructed with the file path\name in fn + * and the extension in ft. + * (2) If the file type specification string ft + * is NULL then the file specification is + * constructed from fn. If fn does not have + * a file type then the default .rel file + * type is appended to the file specification. + * + * afile() returns a file handle for the opened file or aborts + * the assembler on an open error. + * + * local variables: + * char fb[] constructed file specification string + * FILE * fp filehandle for opened file + * + * global variables: + * int lkerr error flag + * + * functions called: + * FILE * fopen() c_library + * int fprintf() c_library + * + * side effects: + * File is opened for read or write. + */ + +FILE * +afile(fn, ft, wf) +char *fn; +char *ft; +{ + FILE *fp; + char fb[PATH_MAX]; + char *omode = (wf ? (wf == 2 ? "a" : "w") : "r"); + int i; + + /*Look backward the name path and get rid of the extension, if any*/ + i=strlen(fn); + for(; (fn[i]!='.')&&(fn[i]!='\\')&&(fn[i]!='/')&&(i>=0); i--); + if( (fn[i]=='.') && strcmp(ft, "lnk") ) + { + strncpy(fb, fn, i); + fb[i]=0; + } + else + { + strcpy(fb, fn); + } + + /*Add the extension*/ + strcat(fb, "."); + strcat(fb, strlen(ft)?ft:"rel"); + + fp = fopen(fb, omode); + if (fp==NULL) + { + if (strcmp(ft,"adb"))/*Do not complaint for optional adb files*/ + { + fprintf(stderr, "%s: cannot %s.\n", fb, wf?"create":"open"); + lkerr++; + } + } + return (fp); +} + +/*)Function VOID iramsav() + * + * The function iramsav() stores the size of the chip's internal RAM. + * This is used after linking to check that variable assignment to this + * dataspace didn't overflow into adjoining segments. Variables in the + * DSEG, OSEG, and ISEG are assigned to this dataspace. + * + * local variables: + * none + * + * global variables: + * char *ip pointer into the REL file + * text line in ib[] + * unsigned int size of chip's internal + * iram_size RAM segment + * + * functions called: + * char getnb() lklex.c + * VOID unget() lklex.c + * Addr_T expr() lkeval.c + * + * side effects: + * The iram_size may be modified. + */ + +VOID +iramsav() +{ + unget(getnb()); + if (ip && *ip) + //iram_size = atoi(ip); + iram_size = expr(0); /* evaluate size expression */ + else + iram_size = 128; /* Default is 128 (0x80) bytes */ +} + +/*Similar to iramsav but for xram memory*/ +VOID +xramsav() +{ + unget(getnb()); + if (ip && *ip) + xram_size = expr(0); /* evaluate size expression */ + else + xram_size = rflag?0x1000000:0x10000; +} + +/*Similar to iramsav but for code memory*/ +VOID +codesav() +{ + unget(getnb()); + if (ip && *ip) + code_size = expr(0); /* evaluate size expression */ + else + code_size = rflag?0x1000000:0x10000; +} + + +/*)Function VOID iramcheck() + * + * The function iramcheck() is used at the end of linking to check that + * the internal RAM area wasn't overflowed by too many variable + * assignments. Variables in the DSEG, ISEG, and OSEG are assigned to + * the chip's internal RAM. + * + * local variables: + * none + * + * global variables: + * unsigned int size of chip's internal + * iram_size RAM segment + * struct area linked list of memory + * *areap areas + * + * functions called: + * + * side effects: + */ + +VOID +iramcheck() +{ + register unsigned int last_addr; + register struct area *ap; + + for (ap = areap; ap; ap=ap->a_ap) { + if ((ap->a_size != 0) && + (!strcmp(ap->a_id, "DSEG") || + !strcmp(ap->a_id, "OSEG") || + !strcmp(ap->a_id, "ISEG") + ) + ) + { + last_addr = ap->a_addr + ap->a_size - 1; + if (last_addr >= iram_size) + fprintf(stderr, + "\nWARNING! Segment %s extends past the end\n" + " of internal RAM. Check map file.\n", + ap->a_id); + } + } +} + +char *usetxt[] = { + "Startup:", + " -c Command line input", + " -f file[LNK] File input", + " -p Prompt and echo of file[LNK] to stdout (default)", + " -n No echo of file[LNK] to stdout", +/* "Usage: [-Options] file [file ...]", */ + "Libraries:", + " -k Library path specification, one per -k", + " -l Library file specification, one per -l", + "Relocation:", + " -b area base address = expression", + " -g global symbol = expression", + "Map format:", + " -m Map output generated as file[MAP]", + " -x Hexadecimal (default), -d Decimal, -q Octal", + "Output:", + " -i Intel Hex as file[IHX]", + " -s Motorola S19 as file[S19]", + " -j Produce NoICE debug as file[NOI]", + " -z Produce SDCdb debug as file[cdb]", +/* "List:", */ + " -u Update listing file(s) with link data as file(s)[.RST]", + "Miscellaneous:\n" + " -a [iram-size] Check for internal RAM overflow", + " -v [xram-size] Check for external RAM overflow", + " -w [code-size] Check for code overflow", + "End:", + " -e or null line terminates input", + 0 +}; + +/*)Function VOID usage() + * + * The function usage() outputs to the stderr device the + * assembler name and version and a list of valid assembler options. + * + * local variables: + * char ** dp pointer to an array of + * text string pointers. + * + * global variables: + * FILE * stderr c_library + * + * functions called: + * int fprintf() c_library + * + * side effects: + * none + */ + +VOID +usage() +{ + register char **dp; + + fprintf(stderr, "\nASxxxx Linker %s\n\n", VERSION); + for (dp = usetxt; *dp; dp++) + fprintf(stderr, "%s\n", *dp); + lkexit(1); +} + +/*)Function VOID copyfile() + * + * FILE *dest destination file + * FILE *src source file + * + * function will copy source file to destination file + * + * + * functions called: + * int fgetc() c_library + * int fputc() c_library + * + * side effects: + * none + */ +VOID copyfile (dest,src) +FILE *src,*dest ; +{ + int ch; + while ((ch = fgetc(src)) != EOF) { + + fputc(ch,dest); + } +} diff --git a/as/hc08/lkmem.c b/as/hc08/lkmem.c new file mode 100644 index 00000000..db9a2cd9 --- /dev/null +++ b/as/hc08/lkmem.c @@ -0,0 +1,361 @@ +/*------------------------------------------------------------------------- + lkmem.c - Create a memory summary file with extension .mem + + Written By - Jesus Calvino-Fraga, jesusc@ieee.org (2002) + + 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 2, 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, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +-------------------------------------------------------------------------*/ + +#include +#include +#include +#include "aslink.h" +#include "strcmpi.h" + +int summary(struct area * areap) +{ + #define EQ(A,B) !as_strcmpi((A),(B)) + #define MIN_STACK 16 + #define REPORT_ERROR(A, H) \ + {\ + fprintf(of, "%s%s", (H)?"*** ERROR: ":"", (A)); \ + fprintf(stderr, "%s%s", (H)?"\n?ASlink-Error-":"",(A)); \ + toreturn=1; \ + } + + #define REPORT_WARNING(A, H) \ + { \ + fprintf(of, "%s%s", (H)?"*** WARNING: ":"", (A)); \ + fprintf(stderr, "%s%s",(H)?"\n?ASlink-Warning-":"", (A)); \ + } + + char buff[128]; + int j, toreturn=0; + unsigned int Total_Last=0, k; + + struct area * xp; + FILE * of; + + /*Artifacts used for printing*/ + char start[15], end[15], size[15], max[15]; + char format[]=" %-16.16s %-8.8s %-8.8s %-8.8s %-8.8s\n"; + char line[]="---------------------"; + + typedef struct + { + unsigned long Start; + unsigned long Size; + unsigned long Max; + char Name[NCPS]; + unsigned long flag; + } _Mem; + + unsigned int dram[0x100]; + _Mem Ram[]={ + {0, 0, 0, "REG_BANK_0", 0x0001}, + {0x0, 0, 0, "REG_BANK_1", 0x0002}, + {0x0, 0, 0, "REG_BANK_2", 0x0004}, + {0x0, 0, 0, "REG_BANK_3", 0x0008}, + {0x0, 0, 0, "BSEG_BYTES", 0x0010}, + {0, 0, 256, "UNUSED", 0x0000}, + {0xff, 0, 256, "DATA", 0x0020}, + {0, 0, 256, "TOTAL:", 0x0000} + }; + + _Mem IRam= {0xff, 0, 0, "INDIRECT RAM", 0x0080}; + _Mem Stack={0xff, 0, 1, "STACK", 0x0000}; + _Mem XRam= {0xffff, 0, 65536, "EXTERNAL RAM", 0x0100}; + _Mem Rom= {0xffff, 0, 65536, "ROM/EPROM/FLASH", 0x0200}; + +#if 0 + if(rflag) /*For the DS390*/ + { + XRam.Max=0x1000000; /*24 bits*/ + XRam.Start=0xffffff; + Rom.Max=0x1000000; + Rom.Start=0xffffff; + } + + if((iram_size<=0)||(iram_size>0x100)) /*Default: 8052 like memory*/ + { + Ram[5].Max=0x80; + Ram[6].Max=0x80; + Ram[7].Max=0x80; + IRam.Max=0x80; + iram_size=0x100; + } + else if(iram_size<0x80) + { + Ram[5].Max=iram_size; + Ram[6].Max=iram_size; + Ram[7].Max=iram_size; + IRam.Max=0; + } + else + { + Ram[5].Max=0x80; + Ram[6].Max=0x80; + Ram[7].Max=0x80; + IRam.Max=iram_size-0x80; + } +#endif + + for(j=0; j<(int)iram_size; j++) dram[j]=0; + for(; j<0x100; j++) dram[j]=0x8000; /*Memory not available*/ + + /* Open Memory Summary File*/ + of = afile(linkp->f_idp, "mem", 1); + if (of == NULL) + { + lkexit(1); + } + + xp=areap; + while (xp) + { + /**/ if (EQ(xp->a_id, "REG_BANK_0")) + { + Ram[0].Size=xp->a_size; + } + else if (EQ(xp->a_id, "REG_BANK_1")) + { + Ram[1].Size=xp->a_size; + } + else if (EQ(xp->a_id, "REG_BANK_2")) + { + Ram[2].Size=xp->a_size; + } + else if (EQ(xp->a_id, "REG_BANK_3")) + { + Ram[3].Size=xp->a_size; + } + else if (EQ(xp->a_id, "BSEG_BYTES")) + { + Ram[4].Size=xp->a_size; + } + else if ( EQ(xp->a_id, "DSEG") || EQ(xp->a_id, "OSEG") ) + { + Ram[6].Size+=xp->a_size; + if(xp->a_addra_addr; + } + + else if( EQ(xp->a_id, "CSEG") || EQ(xp->a_id, "GSINIT") || + EQ(xp->a_id, "GSFINAL") || EQ(xp->a_id, "HOME") ) + { + Rom.Size+=xp->a_size; + if(xp->a_addra_addr; + } + + else if (EQ(xp->a_id, "SSEG")) + { + Stack.Size+=xp->a_size; + if(xp->a_addra_addr; + } + + else if (EQ(xp->a_id, "XSEG") || EQ(xp->a_id, "XISEG")) + { + XRam.Size+=xp->a_size; + if(xp->a_addra_addr; + } + + else if (EQ(xp->a_id, "ISEG")) + { + IRam.Size+=xp->a_size; + if(xp->a_addra_addr; + } + xp=xp->a_ap; + } + + for(j=0; j<7; j++) + for(k=Ram[j].Start; (k<(Ram[j].Start+Ram[j].Size))&&(k<0x100); k++) + dram[k]|=Ram[j].flag; /*Mark as used*/ + +#if 0 + for(k=IRam.Start; (k<(IRam.Start+IRam.Size))&&(k<0x100); k++) + dram[k]|=IRam.flag; /*Mark as used*/ +#endif + + /*Compute the amount of unused memory in direct data Ram. This is the + gap between the last register bank or bit segment and the data segment.*/ + for(k=Ram[6].Start-1; (dram[k]==0) && (k>0); k--); + Ram[5].Start=k+1; + Ram[5].Size=Ram[6].Start-Ram[5].Start; /*It may be zero (which is good!)*/ + + /*Compute the data Ram totals*/ + for(j=0; j<7; j++) + { + if(Ram[7].Start>Ram[j].Start) Ram[7].Start=Ram[j].Start; + Ram[7].Size+=Ram[j].Size; + } + Total_Last=Ram[6].Size+Ram[6].Start-1; + + /*Report the Ram totals*/ + fprintf(of, "Direct Internal RAM:\n"); + fprintf(of, format, "Name", "Start", "End", "Size", "Max"); + + for(j=0; j<8; j++) + { + if((j==0) || (j==7)) fprintf(of, format, line, line, line, line, line); + if((j!=5) || (Ram[j].Size>0)) + { + sprintf(start, "0x%02lx", Ram[j].Start); + if(Ram[j].Size==0) + end[0]=0;/*Empty string*/ + else + sprintf(end, "0x%02lx", j==7?Total_Last:Ram[j].Size+Ram[j].Start-1); + sprintf(size, "%5lu", Ram[j].Size); + sprintf(max, "%5lu", Ram[j].Max); + fprintf(of, format, Ram[j].Name, start, end, size, max); + } + } + +#if 0 + for(k=Ram[6].Start; (k<(Ram[6].Start+Ram[6].Size))&&(k<0x100); k++) + { + if(dram[k]!=Ram[6].flag) + { + sprintf(buff, "Internal memory overlap starting at 0x%02x.\n", k); + REPORT_ERROR(buff, 1); + break; + } + } + + + if(Ram[4].Size>Ram[4].Max) + { + k=Ram[4].Size-Ram[4].Max; + sprintf(buff, "Insufficient bit addressable memory. " + "%d byte%s short.\n", k, (k==1)?"":"s"); + REPORT_ERROR(buff, 1); + } + + if(Ram[5].Size!=0) + { + sprintf(buff, "%ld bytes in data memory wasted. " + "SDCC link could use: --data-loc 0x%02lx\n", + Ram[5].Size, Ram[6].Start-Ram[5].Size); + REPORT_WARNING(buff, 1); + } + + if((Ram[6].Start+Ram[6].Size)>Ram[6].Max) + { + k=(Ram[6].Start+Ram[6].Size)-Ram[6].Max; + sprintf(buff, "Insufficient space in data memory. " + "%d byte%s short.\n", k, (k==1)?"":"s"); + REPORT_ERROR(buff, 1); + } +#endif + /*Report the position of the begining of the stack*/ + fprintf(of, "\n%stack starts at: 0x%02lx (sp set to 0x%02lx)", + rflag ? "16 bit mode initial s" : "S", Stack.Start, Stack.Start-1); + +#if 0 + /*Check that the stack pointer is landing in a safe place:*/ + if( (dram[Stack.Start] & 0x8000) == 0x8000 ) + { + fprintf(of, ".\n"); + sprintf(buff, "Stack set to unavailable memory.\n"); + REPORT_ERROR(buff, 1); + } + else if(dram[Stack.Start]) + { + fprintf(of, ".\n"); + sprintf(buff, "Stack overlaps area "); + REPORT_ERROR(buff, 1); + for(j=0; j<7; j++) + { + if(dram[Stack.Start]&Ram[j].flag) + { + sprintf(buff, "'%s'\n", Ram[j].Name); + break; + } + } + if(dram[Stack.Start]&IRam.flag) + { + sprintf(buff, "'%s'\n", IRam.Name); + } + REPORT_ERROR(buff, 0); + } + else + { + for(j=Stack.Start, k=0; (j<(int)iram_size)&&(dram[j]==0); j++, k++); + fprintf(of, " with %d bytes available\n", k); + if (k(IRam.Max+0x80)) + { + sprintf(buff, "Insufficient INDIRECT RAM memory.\n"); + REPORT_ERROR(buff, 1); + } +#endif + if( ((XRam.Start+XRam.Size)>XRam.Max) || + (((int)XRam.Size>xram_size)&&(xram_size>=0)) ) + { + sprintf(buff, "Insufficient EXTERNAL RAM memory.\n"); + REPORT_ERROR(buff, 1); + } + if( ((Rom.Start+Rom.Size)>Rom.Max) || + (((int)Rom.Size>code_size)&&(code_size>=0)) ) + { + sprintf(buff, "Insufficient ROM/EPROM/FLASH memory.\n"); + REPORT_ERROR(buff, 1); + } + + fclose(of); + return toreturn; +} diff --git a/as/hc08/lknoice.c b/as/hc08/lknoice.c new file mode 100644 index 00000000..2cd6a91c --- /dev/null +++ b/as/hc08/lknoice.c @@ -0,0 +1,246 @@ +/* lknoice.c */ + +/* + * Extensions to CUG 292 linker ASLINK to produce NoICE debug files + * + * 31-Oct-1997 by John Hartman + * 30-Jan-98 JLH add page to DefineNoICE for 8051 + * 2-Feb-98 JLH Allow optional .nest on local vars - C scoping rules... + */ + +#include +#include +#include +#include "aslink.h" +#include "strcmpi.h" + +static void DefineGlobal( char *name, Addr_T value, int page ); +static void DefineScoped( char *name, Addr_T value, int page ); +static void DefineFile( char *name, Addr_T value, int page ); +static void DefineFunction( char *name, Addr_T value, int page ); +static void DefineStaticFunction( char *name, Addr_T value, int page ); +static void DefineEndFunction( Addr_T value, int page ); +static void DefineLine( char *lineString, Addr_T value, int page ); +static void PagedAddress( Addr_T value, int page ); + +/* + * Called from lstarea in lklist.c for each symbol. + * + * Generates appropriate NoICE commands into output file, if any is open + * + */ +void DefineNoICE( char *name, Addr_T value, int page ) +{ + char token1[NCPS]; /* parse for file.function.symbol */ + char token2[NCPS]; + char token3[NCPS]; + // char token4[NCPS]; + char sep1, sep2; + int j, level; + + /* no output if file is not open */ + if (jfp == NULL) return; + + j = sscanf( name, "%[^.]%c%[^.]%c%s", + token1, &sep1, token2, &sep2, token3 ); + switch (j) + { + /* file.function.symbol, or file.function..SPECIAL */ + case 5: + DefineFile( token1, 0, 0 ); + if (token3[0] == '.') + { + if (strcmp( token3, ".FN" ) == 0) + { + /* Global function */ + DefineFunction( token2, value, page ); + } + else if (strcmp( token3, ".SFN" ) == 0) + { + /* Static (file-scope) function */ + DefineStaticFunction( token2, value, page ); + } + else if (strcmp( token3, ".EFN" ) == 0) + { + /* End of function */ + DefineEndFunction( value, page ); + } + } + else + { + /* Function-scope var. */ + DefineFunction( token2, 0, 0 ); + + /* Look for optional level integer */ + j = sscanf( token3, "%[^.]%c%u", token1, &sep1, &level ); + if ((j == 3) && (level != 0)) + { + sprintf( &token1[ strlen(token1) ], "_%u", level ); + } + DefineScoped( token1, value, page ); + } + break; + + /* file.func. is illegal */ + case 4: + break; + + /* either file.symbol or file.line# */ + case 3: + DefineFile( token1, 0, 0 ); + if ((token2[0] >= '0') && (token2[0] <= '9')) + { + /* Line number */ + DefineLine( token2, value, page ); + } + else + { + /* File-scope symbol. (Kill any function) */ + DefineEndFunction( 0, 0 ); + DefineScoped( token2, value, page ); + } + break; + + /* symbol. is illegal */ + case 2: + break; + + /* just a symbol */ + case 1: + DefineGlobal( token1, value, page ); + break; + } +} + +static char currentFile[NCPS]; +static char currentFunction[NCPS]; + +/* + * static function: + * Define "name" as a global symbol + */ +void DefineGlobal( char *name, Addr_T value, int page ) +{ + fprintf( jfp, "DEF %s ", name ); + PagedAddress( value, page ); +} + +/* + * static function: + * Define "name" as a static (scoped) symbol + */ +void DefineScoped( char *name, Addr_T value, int page ) +{ + fprintf( jfp, "DEFS %s ", name ); + PagedAddress( value, page ); +} + +/* + * static function: + * Define "name" as the current file + */ +void DefineFile( char *name, Addr_T value, int page ) +{ + if (as_strcmpi( name, currentFile ) != 0) + { + strcpy( currentFile, name ); + if (value != 0) + { + fprintf( jfp, "FILE %s ", name ); + PagedAddress( value, page ); + } + else + { + fprintf( jfp, "FILE %s\n", name ); + } + } +} + +/* + * static function: + * Define "name" as the current function + */ +void DefineFunction( char *name, Addr_T value, int page ) +{ + if (as_strcmpi( name, currentFunction ) != 0) + { + strcpy( currentFunction, name ); + if (value != 0) + { + fprintf( jfp, "DEF %s ", name ); + PagedAddress( value, page ); + fprintf( jfp, "FUNC %s ", name ); + PagedAddress( value, page ); + } + else + { + fprintf( jfp, "FUNC %s\n", name ); + } + } +} + +/* + * static function: + * Define "name" as the current static (scoped) function + */ +void DefineStaticFunction( char *name, Addr_T value, int page ) +{ + if (as_strcmpi( name, currentFunction ) != 0) + { + strcpy( currentFunction, name ); + if (value != 0) + { + fprintf( jfp, "DEFS %s ", name ); + PagedAddress( value, page ); + fprintf( jfp, "SFUNC %s ", name ); + PagedAddress( value, page ); + } + else + { + fprintf( jfp, "SFUNC %s\n", name ); + } + } +} + +/* + * static function: + * Define the end of the current function + */ +void DefineEndFunction( Addr_T value, int page ) +{ + if (currentFunction[0] != 0) + { + if (value != 0) + { + fprintf( jfp, "ENDF " ); + PagedAddress( value, page ); + } + else + { + fprintf( jfp, "ENDF\n" ); + } + + currentFunction[0] = 0; + } +} + +/* + * static function: + * Define "lineNumber" as a line in the current file + */ +void DefineLine( char *lineString, Addr_T value, int page ) +{ + int indigit, lineNumber = 0; + + while( (indigit=digit( *lineString++, 10 )) >= 0) + { + lineNumber = 10*lineNumber + indigit; + } + fprintf( jfp, "LINE %u ", lineNumber ); + PagedAddress( value, page ); +} + +void PagedAddress( Addr_T value, int page ) +{ + fprintf( jfp, "%X:0x%X\n", page, value ); +} diff --git a/as/hc08/lkrloc.c b/as/hc08/lkrloc.c new file mode 100644 index 00000000..cf761024 --- /dev/null +++ b/as/hc08/lkrloc.c @@ -0,0 +1,1473 @@ +/* lkrloc.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + * + * 29-Oct-97 JLH: + * - errdmp: show s_id as string rather than array [NCPS] + * - relr: add support for 11 bit 8051 addressing + * 02-Apr-98 JLH: don't output empty hex records + */ + +#include +#include +#include "aslink.h" + +/*)Module lkrloc.c + * + * The module lkrloc.c contains the functions which + * perform the relocation calculations. + * + * lkrloc.c contains the following functions: + * Addr_T adb_b() + * Addr_T adb_lo() + * Addr_T adb_hi() + * Addr_T adw_w() + * Addr_T adw_lo() + * Addr_T adw_hi() + * VOID erpdmp() + * VOID errdmp() + * Addr_T evword() + * VOID prntval() + * VOID rele() + * VOID relerr() + * VOID relerp() + * VOID reloc() + * VOID relp() + * VOID relr() + * VOID relt() + * + * lkrloc.c the local variable errmsg[]. + * + */ + +/* Global which holds the upper 16 bits of the last 32 bit area adress + * output. Useful only for iHex mode. + */ +int lastExtendedAddress=-1; + +/* Static variable which holds the index of last processed area. + * Useful only for iHex mode. + */ +static int lastAreaIndex = -1; + +/*)Function VOID reloc(c) + * + * char c process code + * + * The function reloc() calls a particular relocation + * function determined by the process code. + * + * local variable: + * none + * + * global variables: + * int lkerr error flag + * + * called functions: + * int fprintf() c_library + * VOID rele() lkrloc.c + * VOID relp() lkrloc.c + * VOID relr() lkrloc.c + * VOId relt() lkrloc.c + * + * side effects: + * Refer to the called relocation functions. + * + */ + +VOID +reloc(c) +char c; +{ + switch(c) { + + case 'T': + relt(); + break; + + case 'R': + relr(); + break; + + case 'P': + relp(); + break; + + case 'E': + rele(); + break; + + default: + fprintf(stderr, "Undefined Relocation Operation\n"); + lkerr++; + break; + + } +} + + +/*)Function VOID relt() + * + * The function relt() evaluates a T line read by + * the linker. Each byte value read is saved in the + * rtval[] array, rtflg[] is set, and the number of + * evaluations is maintained in rtcnt. + * + * T Line + * + * T xx xx nn nn nn nn nn ... + * + * + * In: "T n0 n1 n2 n3 ... nn" + * + * Out: 0 1 2 .. rtcnt + * +----+----+----+----+----+ + * rtval | n0 | n1 | n2 | .. | nn | + * +----+----+----+----+----+ + * rtflag| 1 | 1 | 1 | 1 | 1 | + * +----+----+----+----+----+ + * + * The T line contains the assembled code output by the assem- + * bler with xx xx being the offset address from the current area + * base address and nn being the assembled instructions and data in + * byte format. + * + * local variable: + * none + * + * global variables: + * int rtcnt number of values evaluated + * int rtflg[] array of evaluation flags + * int rtval[] array of evaluation values + * + * called functions: + * int eval() lkeval.c + * int more() lklex.c + * + * side effects: + * Linker input T line evaluated. + * + */ + +VOID +relt() +{ + rtcnt = 0; + while (more()) { + if (rtcnt < NTXT) { + rtval[rtcnt] = eval(); + rtflg[rtcnt] = 1; + rtcnt++; + } + } +} + +/*)Function VOID relr() + * + * The function relr() evaluates a R line read by + * the linker. The R line data is combined with the + * previous T line data to perform the relocation of + * code and data bytes. The S19 / IHX output and + * translation of the LST files to RST files may be + * performed. + * + * R Line + * + * R 0 0 nn nn n1 n2 xx xx ... + * + * The R line provides the relocation information to the linker. + * The nn nn value is the current area index, i.e. which area the + * current values were assembled. Relocation information is en- + * coded in groups of 4 bytes: + * + * 1. n1 is the relocation mode and object format + * 1. bit 0 word(0x00)/byte(0x01) + * 2. bit 1 relocatable area(0x00)/symbol(0x02) + * 3. bit 2 normal(0x00)/PC relative(0x04) relocation + * 4. bit 3 1-byte(0x00)/2-byte(0x08) object format for + * byte data + * 5. bit 4 signed(0x00)/unsigned(0x10) byte data + * 6. bit 5 normal(0x00)/page '0'(0x20) reference + * 7. bit 6 normal(0x00)/page 'nnn'(0x40) reference + * + * 2. n2 is a byte index into the corresponding (i.e. pre- + * ceeding) T line data (i.e. a pointer to the data to be + * updated by the relocation). The T line data may be + * 1-byte or 2-byte byte data format or 2-byte word + * format. + * + * 3. xx xx is the area/symbol index for the area/symbol be- + * ing referenced. the corresponding area/symbol is found + * in the header area/symbol lists. + * + * The groups of 4 bytes are repeated for each item requiring relo- + * cation in the preceeding T line. + * + * local variable: + * areax **a pointer to array of area pointers + * int aindex area index + * char *errmsg[] array of pointers to error strings + * int error error code + * int lkerr error flag + * int mode relocation mode + * adrr_t paga paging base area address + * Addr_T pags paging symbol address + * Addr_T pc relocated base address + * Addr_T r PCR relocation value + * Addr_T reli relocation initial value + * Addr_T relv relocation final value + * int rindex symbol / area index + * Addr_T rtbase base code address + * Addr_T rtofst rtval[] index offset + * int rtp index into T data + * sym **s pointer to array of symbol pointers + * + * global variables: + * head *hp pointer to the head structure + * rerr rerr linker error structure + * FILE *stderr standard error device + * + * called functions: + * Addr_T adb_b() lkrloc.c + * Addr_T adb_lo() lkrloc.c + * Addr_T adb_hi() lkrloc.c + * Addr_T adw_w() lkrloc.c + * Addr_T evword() lkrloc.c + * int eval() lkeval.c + * int fprintf() c_library + * VOID ihx() lkihx.c + * int lkulist lklist.c + * int more() lklex.c + * VOID relerr() lkrloc.c + * VOID s19() lks19.c + * int symval() lksym.c + * + * side effects: + * The R and T lines are combined to produce + * relocated code and data. Output S19 / IHX + * and relocated listing files may be produced. + * + */ + +VOID +relr() +{ + register int mode; + register Addr_T reli, relv; + int aindex, rindex, rtp, error; + Addr_T r, rtbase, rtofst, paga, pags, pc; + struct areax **a; + struct sym **s; + + /* + * Get area and symbol lists + */ + a = hp->a_list; + s = hp->s_list; + + /* + * Verify Area Mode + */ + if (eval() != (R_WORD | R_AREA) || eval()) { + fprintf(stderr, "R input error\n"); + lkerr++; + } + + /* + * Get area pointer + */ + aindex = evword(); + if (aindex >= hp->h_narea) { + fprintf(stderr, "R area error\n"); + lkerr++; + return; + } + + /* + * Base values + */ + rtbase = adw_w(0, 0); + rtofst = 2; + + /* + * Relocate address + */ + pc = adw_w(a[aindex]->a_addr, 0); + + #if 0 + printf("area %d base address: 0x%x size: 0x%x rtbase: 0x%x\n", aindex, + a[aindex]->a_addr, a[aindex]->a_size, rtbase); + #endif + /* + * Do remaining relocations + */ + while (more()) { + error = 0; + mode = eval(); + + if ((mode & R_ESCAPE_MASK) == R_ESCAPE_MASK) + { + mode = ((mode & ~R_ESCAPE_MASK) << 8) | eval(); + /* printf("unescaping rmode\n"); */ + } + + rtp = eval(); + rindex = evword(); + + /* + * R_SYM or R_AREA references + */ + if (mode & R_SYM) { + if (rindex >= hp->h_nglob) { + fprintf(stderr, "R symbol error\n"); + lkerr++; + return; + } + reli = symval(s[rindex]); + } else { + if (rindex >= hp->h_narea) { + fprintf(stderr, "R area error\n"); + lkerr++; + return; + } + reli = a[rindex]->a_addr; + } + + /* + * R_PCR addressing + */ + if (mode & R_PCR) { + if (mode & R_BYTE) { + reli -= (pc + (rtp-rtofst) + 1); + } else { + reli -= (pc + (rtp-rtofst) + 2); + } + } + + /* + * R_PAG0 or R_PAG addressing + */ + if (mode & (R_PAG0 | R_PAG)) { + paga = sdp.s_area->a_addr; + pags = sdp.s_addr; + reli -= paga + pags; + } + + /* + * R_BYTE or R_WORD operation + */ + if (mode & R_BYTE) { + if (mode & R_BYT3) + { + /* This is a three byte address, of which + * we will select one byte. + */ + if (mode & R_HIB) + { + /* printf("24 bit address selecting hi byte.\n"); */ + relv = adb_24_hi(reli, rtp); + } + else if (mode & R_MSB) + { + /* Note that in 24 bit mode, R_MSB + * is really the middle byte, not + * the most significant byte. + * + * This is ugly and I can only apologize + * for any confusion. + */ + /* printf("24 bit address selecting middle byte.\n"); */ + relv = adb_24_mid(reli, rtp); + } + else + { + /* printf("24 bit address selecting lo byte.\n"); */ + relv = adb_24_lo(reli, rtp); + } + } + else if (mode & R_BYT2) { + /* This is a two byte address, of + * which we will select one byte. + */ + if (mode & R_MSB) { + relv = adb_hi(reli, rtp); + } else { + relv = adb_lo(reli, rtp); + } + } else { + relv = adb_b(reli, rtp); + } + } else if (IS_R_J11(mode)) { + /* JLH: 11 bit jump destination for 8051. Forms + / two byte instruction with op-code bits + / in the MIDDLE! + / rtp points at 3 byte locus: first two + / will get the instructiion. third one + / has raw op-code. + */ + + /* Calculate absolute destination + / relv must be on same 2K page as pc + */ + relv = adw_w(reli, rtp); + + if ((relv & ~0x7ff) != ((pc + rtp - rtofst) & ~0x7ff)) { + error = 2; + } + + /* Merge MSB (byte 0) with op-code, ignoring + / top 5 bits of address. Then hide the op-code + */ + rtval[rtp] = ((rtval[rtp] & 0x07)<<5) | rtval[rtp+2]; + rtflg[rtp+2] = 0; + rtofst += 1; + } + else if (IS_R_J19(mode)) { + /* 19 bit jump destination for DS80C390. Forms + / three byte instruction with op-code bits + / in the MIDDLE! + / rtp points at 4 byte locus: first three + / will get the instructiion. fourth one + / has raw op-code. + */ + + /* Calculate absolute destination + / relv must be on same 512K page as pc + */ + relv = adw_24(reli, rtp); + + if ((relv & ~0x7ffff) != ((pc + rtp - rtofst) & ~0x7ffff)) { + error = 2; + } + + /* Merge MSB (byte 0) with op-code, ignoring + / top 5 bits of address. Then hide the op-code + */ + rtval[rtp] = ((rtval[rtp] & 0x07)<<5) | rtval[rtp+3]; + rtflg[rtp+3] = 0; + rtofst += 1; + } + else if (IS_C24(mode)) + { + /* 24 bit address */ + relv = adw_24(reli, rtp); + } + else + { + /* 16 bit address. */ + relv = adw_w(reli, rtp); + } + + /* + * R_BYTE with R_BYT2 offset adjust + */ + if (mode & R_BYTE) { + if (mode & R_BYT2) { + rtofst += 1; + } + } + + /* + * Unsigned Byte Checking + */ + if (mode & R_USGN && mode & R_BYTE && relv & ~0xFF) + error = 1; + + /* + * PCR Relocation Error Checking + */ + if (mode & R_PCR && mode & R_BYTE) { + r = relv & ~0x7F; + if (r != (Addr_T) ~0x7F && r != 0) + error = 2; + } + + /* + * Page Relocation Error Checking + */ + /* if (mode & R_PAG0 && (relv & ~0xFF || paga || pags)) + error = 3;*/ + if (mode & R_PAG && (relv & ~0xFF)) + error = 4; + + /* + * Error Processing + */ + if (error) { + rerr.aindex = aindex; + rerr.mode = mode; + rerr.rtbase = rtbase + rtp - rtofst - 1; + rerr.rindex = rindex; + rerr.rval = relv - reli; + relerr(errmsg[error-1]); + } + } + if (uflag != 0) { + lkulist(1); + } + + + /* JLH: output only if data (beyond two byte address) */ + if ((oflag == 1) && (rtcnt > 2)) { + int extendedAddress = (a[aindex]->a_addr >> 16) & 0xffff; + + /* Boy, is this a hack: for ABS sections, the + * base address is stored as zero, and the T records + * indicate the offset from zero. + * + * Since T records can only indicate a 16 bit offset, this + * obviously creates a problem for ABS segments located + * above 64K (this is only meaningful in flat24 mode). + * + * However, the size of an ABS area is stored as + * base address + section size (I suspect this is a bug, + * but it's a handy one right now). So the upper 8 bits of + * the 24 bit address are stored in the size record. + * Thus we add it in. + * + * This is another reason why we can't have areas greater + * than 64K yet, even in flat24 mode. + */ + // extendedAddress += ((a[aindex]->a_size) >> 16 & 0xffff); + // commented out by jr + + if (lastAreaIndex != aindex) { + lastAreaIndex = aindex; + newArea(); + } + +#if 0 + if (extendedAddress != lastExtendedAddress) + { + + if (lastExtendedAddress!=-1) { + printf("output extended linear address record 0x%x 0x%x\n", + extendedAddress, lastExtendedAddress); + } + + if (rflag) + { + ihxEntendedLinearAddress(extendedAddress); + } + else if (extendedAddress) + { + /* Not allowed to generate extended address records, + * but one is called for here... + */ + fprintf(stderr, + "warning: extended linear address encountered; " + "you probably want the -r flag.\n"); + } + lastExtendedAddress = extendedAddress; + } +#endif + ihx(1); + } else + if ((oflag == 2) && (rtcnt > 2)) { + s19(1); + } +} + +char *errmsg[] = { + "Unsigned Byte error", + "Byte PCR relocation error", + "Page0 relocation error", + "Page Mode relocation error" +}; + + +/*)Function VOID relp() + * + * The function relp() evaluates a P line read by + * the linker. The P line data is combined with the + * previous T line data to set the base page address + * and test the paging boundary and length. + * + * P Line + * + * P 0 0 nn nn n1 n2 xx xx + * + * The P line provides the paging information to the linker as + * specified by a .setdp directive. The format of the relocation + * information is identical to that of the R line. The correspond- + * ing T line has the following information: + * T xx xx aa aa bb bb + * + * Where aa aa is the area reference number which specifies the + * selected page area and bb bb is the base address of the page. + * bb bb will require relocation processing if the 'n1 n2 xx xx' is + * specified in the P line. The linker will verify that the base + * address is on a 256 byte boundary and that the page length of an + * area defined with the PAG type is not larger than 256 bytes. + * + * local variable: + * areax **a pointer to array of area pointers + * int aindex area index + * int mode relocation mode + * Addr_T relv relocation value + * int rindex symbol / area index + * int rtp index into T data + * sym **s pointer to array of symbol pointers + * + * global variables: + * head *hp pointer to the head structure + * int lkerr error flag + * sdp sdp base page structure + * FILE *stderr standard error device + * + * called functions: + * Addr_T adw_w() lkrloc.c + * Addr_T evword() lkrloc.c + * int eval() lkeval.c + * int fprintf() c_library + * int more() lklex.c + * int symval() lksym.c + * + * side effects: + * The P and T lines are combined to set + * the base page address and report any + * paging errors. + * + */ + +VOID +relp() +{ + register int aindex, rindex; + int mode, rtp; + Addr_T relv; + struct areax **a; + struct sym **s; + + /* + * Get area and symbol lists + */ + a = hp->a_list; + s = hp->s_list; + + /* + * Verify Area Mode + */ + if (eval() != (R_WORD | R_AREA) || eval()) { + fprintf(stderr, "P input error\n"); + lkerr++; + } + + /* + * Get area pointer + */ + aindex = evword(); + if (aindex >= hp->h_narea) { + fprintf(stderr, "P area error\n"); + lkerr++; + return; + } + + /* + * Do remaining relocations + */ + while (more()) { + mode = eval(); + rtp = eval(); + rindex = evword(); + + /* + * R_SYM or R_AREA references + */ + if (mode & R_SYM) { + if (rindex >= hp->h_nglob) { + fprintf(stderr, "P symbol error\n"); + lkerr++; + return; + } + relv = symval(s[rindex]); + } else { + if (rindex >= hp->h_narea) { + fprintf(stderr, "P area error\n"); + lkerr++; + return; + } + relv = a[rindex]->a_addr; + } + adw_w(relv, rtp); + } + + /* + * Paged values + */ + aindex = adw_w(0,2); + if (aindex >= hp->h_narea) { + fprintf(stderr, "P area error\n"); + lkerr++; + return; + } + sdp.s_areax = a[aindex]; + sdp.s_area = sdp.s_areax->a_bap; + sdp.s_addr = adw_w(0,4); + if (sdp.s_area->a_addr & 0xFF || sdp.s_addr & 0xFF) + relerp("Page Definition Boundary Error"); +} + +/*)Function VOID rele() + * + * The function rele() closes all open output files + * at the end of the linking process. + * + * local variable: + * none + * + * global variables: + * int oflag output type flag + * int uflag relocation listing flag + * + * called functions: + * VOID ihx() lkihx.c + * VOID lkulist() lklist.c + * VOID s19() lks19.c + * + * side effects: + * All open output files are closed. + * + */ + +VOID +rele() +{ + if (uflag != 0) { + lkulist(0); + } + if (oflag == 1) { + ihx(0); + } else + if (oflag == 2) { + s19(0); + } +} + +/*)Function Addr_T evword() + * + * The function evword() combines two byte values + * into a single word value. + * + * local variable: + * Addr_T v temporary evaluation variable + * + * global variables: + * hilo byte ordering parameter + * + * called functions: + * int eval() lkeval.c + * + * side effects: + * Relocation text line is scanned to combine + * two byte values into a single word value. + * + */ + +Addr_T +evword() +{ + register Addr_T v; + + if (hilo) { + v = (eval() << 8); + v += eval(); + } else { + v = eval(); + v += (eval() << 8); + } + return(v); +} + +/*)Function Addr_T adb_b(v, i) + * + * int v value to add to byte + * int i rtval[] index + * + * The function adb_b() adds the value of v to + * the single byte value contained in rtval[i]. + * The new value of rtval[i] is returned. + * + * local variable: + * none + * + * global variables: + * none + * + * called functions: + * none + * + * side effects: + * The value of rtval[] is changed. + * + */ + +Addr_T +adb_b(v, i) +register Addr_T v; +register int i; +{ + return(rtval[i] += v); +} + +/*)Function Addr_T adb_lo(v, i) + * + * int v value to add to byte + * int i rtval[] index + * + * The function adb_lo() adds the value of v to the + * double byte value contained in rtval[i] and rtval[i+1]. + * The new value of rtval[i] / rtval[i+1] is returned. + * The MSB rtflg[] is cleared. + * + * local variable: + * Addr_T j temporary evaluation variable + * + * global variables: + * hilo byte ordering parameter + * + * called functions: + * none + * + * side effects: + * The value of rtval[] is changed. + * The rtflg[] value corresponding to the + * MSB of the word value is cleared to reflect + * the fact that the LSB is the selected byte. + * + */ + +Addr_T +adb_lo(v, i) +Addr_T v; +int i; +{ + register Addr_T j; + + j = adw_w(v, i); + /* + * Remove Hi byte + */ + if (hilo) { + rtflg[i] = 0; + } else { + rtflg[i+1] = 0; + } + return (j); +} + +/*)Function Addr_T adb_hi(v, i) + * + * int v value to add to byte + * int i rtval[] index + * + * The function adb_hi() adds the value of v to the + * double byte value contained in rtval[i] and rtval[i+1]. + * The new value of rtval[i] / rtval[i+1] is returned. + * The LSB rtflg[] is cleared. + * + * local variable: + * Addr_T j temporary evaluation variable + * + * global variables: + * hilo byte ordering parameter + * + * called functions: + * none + * + * side effects: + * The value of rtval[] is changed. + * The rtflg[] value corresponding to the + * LSB of the word value is cleared to reflect + * the fact that the MSB is the selected byte. + * + */ + +Addr_T +adb_hi(v, i) +Addr_T v; +int i; +{ + register Addr_T j; + + j = adw_w(v, i); + /* + * Remove Lo byte + */ + if (hilo) { + rtflg[i+1] = 0; + } else { + rtflg[i] = 0; + } + return (j); +} + +/*)Function Addr_T adb_24_hi(v, i) + * + * int v value to add to byte + * int i rtval[] index + * + * The function adb_24_hi() adds the value of v to the + * 24 bit value contained in rtval[i] - rtval[i+2]. + * The new value of rtval[i] / rtval[i+1] is returned. + * The LSB & middle byte rtflg[] is cleared. + * + * local variable: + * Addr_T j temporary evaluation variable + * + * global variables: + * hilo byte ordering parameter + * + * called functions: + * none + * + * side effects: + * The value of rtval[] is changed. + * The rtflg[] value corresponding to the + * LSB & middle byte of the word value is cleared to + * reflect the fact that the MSB is the selected byte. + * + */ + +Addr_T +adb_24_hi(Addr_T v, int i) +{ + register Addr_T j; + + j = adw_24(v, i); + + /* Remove the lower two bytes. */ + if (hilo) + { + rtflg[i+2] = 0; + } + else + { + rtflg[i] = 0; + } + rtflg[i+1] = 0; + + return (j); +} + +/*)Function Addr_T adb_24_mid(v, i) + * + * int v value to add to byte + * int i rtval[] index + * + * The function adb_24_mid() adds the value of v to the + * 24 bit value contained in rtval[i] - rtval[i+2]. + * The new value of rtval[i] / rtval[i+1] is returned. + * The LSB & MSB byte rtflg[] is cleared. + * + * local variable: + * Addr_T j temporary evaluation variable + * + * global variables: + * hilo byte ordering parameter + * + * called functions: + * none + * + * side effects: + * The value of rtval[] is changed. + * The rtflg[] value corresponding to the + * LSB & MSB of the 24 bit value is cleared to reflect + * the fact that the middle byte is the selected byte. + * + */ + +Addr_T +adb_24_mid(Addr_T v, int i) +{ + register Addr_T j; + + j = adw_24(v, i); + + /* remove the MSB & LSB. */ + rtflg[i+2] = 0; + rtflg[i] = 0; + + return (j); +} + +/*)Function Addr_T adb_24_lo(v, i) + * + * int v value to add to byte + * int i rtval[] index + * + * The function adb_24_lo() adds the value of v to the + * 24 bit value contained in rtval[i] - rtval[i+2]. + * The new value of rtval[i] / rtval[i+1] is returned. + * The MSB & middle byte rtflg[] is cleared. + * + * local variable: + * Addr_T j temporary evaluation variable + * + * global variables: + * hilo byte ordering parameter + * + * called functions: + * none + * + * side effects: + * The value of rtval[] is changed. + * The rtflg[] value corresponding to the + * MSB & middle byte of the word value is cleared to + * reflect the fact that the LSB is the selected byte. + * + */ + +Addr_T +adb_24_lo(Addr_T v, int i) +{ + register Addr_T j; + + j = adw_24(v, i); + + /* Remove the upper two bytes. */ + if (hilo) + { + rtflg[i] = 0; + } + else + { + rtflg[i+2] = 0; + } + rtflg[i+1] = 0; + + return (j); +} + +/*)Function Addr_T adw_w(v, i) + * + * int v value to add to word + * int i rtval[] index + * + * The function adw_w() adds the value of v to the + * word value contained in rtval[i] and rtval[i+1]. + * The new value of rtval[i] / rtval[i+1] is returned. + * + * local variable: + * Addr_T j temporary evaluation variable + * + * global variables: + * hilo byte ordering parameter + * + * called functions: + * none + * + * side effects: + * The word value of rtval[] is changed. + * + */ + +Addr_T +adw_w(v, i) +register Addr_T v; +register int i; +{ + register Addr_T j; + + if (hilo) { + j = v + (rtval[i] << 8) + (rtval[i+1] & 0xff); + rtval[i] = (j >> 8) & 0xff; + rtval[i+1] = j & 0xff; + } else { + j = v + (rtval[i] & 0xff) + (rtval[i+1] << 8); + rtval[i] = j & 0xff; + rtval[i+1] = (j >> 8) & 0xff; + } + return(j); +} + +/*)Function Addr_T adw_24(v, i) + * + * int v value to add to word + * int i rtval[] index + * + * The function adw_w() adds the value of v to the + * 24 bit value contained in rtval[i] - rtval[i+2]. + * The new value of rtval[i] - rtval[i+2] is returned. + * + * local variable: + * Addr_T j temporary evaluation variable + * + * global variables: + * hilo byte ordering parameter + * + * called functions: + * none + * + * side effects: + * The word value of rtval[] is changed. + * + */ +Addr_T +adw_24(Addr_T v, int i) +{ + register Addr_T j; + + if (hilo) { + j = v + ((rtval[i] & 0xff) << 16) + + ((rtval[i+1] & 0xff) << 8) + + (rtval[i+2] & 0xff); + rtval[i] = (j >> 16) & 0xff; + rtval[i+1] = (j >> 8) & 0xff; + rtval[i+2] = j & 0xff; + } else { + j = v + (rtval[i] & 0xff) + + ((rtval[i+1] & 0xff) << 8) + + ((rtval[i+2] & 0xff) << 16); + rtval[i] = j & 0xff; + rtval[i+1] = (j >> 8) & 0xff; + rtval[i+2] = (j >> 16) & 0xff; + } + return(j); +} + +/*)Function Addr_T adw_lo(v, i) + * + * int v value to add to byte + * int i rtval[] index + * + * The function adw_lo() adds the value of v to the + * double byte value contained in rtval[i] and rtval[i+1]. + * The new value of rtval[i] / rtval[i+1] is returned. + * The MSB rtval[] is zeroed. + * + * local variable: + * Addr_T j temporary evaluation variable + * + * global variables: + * hilo byte ordering parameter + * + * called functions: + * none + * + * side effects: + * The value of rtval[] is changed. + * The MSB of the word value is cleared to reflect + * the fact that the LSB is the selected byte. + * + */ + +Addr_T +adw_lo(v, i) +Addr_T v; +int i; +{ + register Addr_T j; + + j = adw_w(v, i); + /* + * Clear Hi byte + */ + if (hilo) { + rtval[i] = 0; + } else { + rtval[i+1] = 0; + } + return (j); +} + +/*)Function Addr_T adw_hi(v, i) + * + * int v value to add to byte + * int i rtval[] index + * + * The function adw_hi() adds the value of v to the + * double byte value contained in rtval[i] and rtval[i+1]. + * The new value of rtval[i] / rtval[i+1] is returned. + * The MSB and LSB values are interchanged. + * The MSB rtval[] is zeroed. + * + * local variable: + * Addr_T j temporary evaluation variable + * + * global variables: + * hilo byte ordering parameter + * + * called functions: + * none + * + * side effects: + * The value of rtval[] is changed. + * The MSB and LSB values are interchanged and + * then the MSB cleared. + * + */ + +Addr_T +adw_hi(v, i) +Addr_T v; +int i; +{ + register Addr_T j; + + j = adw_w(v, i); + /* + * LSB = MSB, Clear MSB + */ + if (hilo) { + rtval[i+1] = rtval[i]; + rtval[i] = 0; + } else { + rtval[i] = rtval[i+1]; + rtval[i+1] = 0; + } + return (j); +} + +/*)Function VOID relerr(str) + * + * char *str error string + * + * The function relerr() outputs the error string to + * stderr and to the map file (if it is open). + * + * local variable: + * none + * + * global variables: + * FILE *mfp handle for the map file + * + * called functions: + * VOID errdmp() lkrloc.c + * + * side effects: + * Error message inserted into map file. + * + */ + +VOID +relerr(str) +char *str; +{ + errdmp(stderr, str); + if (mfp) + errdmp(mfp, str); +} + +/*)Function VOID errdmp(fptr, str) + * + * FILE *fptr output file handle + * char *str error string + * + * The function errdmp() outputs the error string str + * to the device specified by fptr. Additional information + * is output about the definition and referencing of + * the symbol / area error. + * + * local variable: + * int mode error mode + * int aindex area index + * int lkerr error flag + * int rindex error index + * sym **s pointer to array of symbol pointers + * areax **a pointer to array of area pointers + * areax *raxp error area extension pointer + * + * global variables: + * sdp sdp base page structure + * + * called functions: + * int fprintf() c_library + * VOID prntval() lkrloc.c + * + * side effects: + * Error reported. + * + */ + +VOID +errdmp(fptr, str) +FILE *fptr; +char *str; +{ + int mode, aindex, rindex; + struct sym **s; + struct areax **a; + struct areax *raxp; + + a = hp->a_list; + s = hp->s_list; + + mode = rerr.mode; + aindex = rerr.aindex; + rindex = rerr.rindex; + + /* + * Print Error + */ + fprintf(fptr, "\n?ASlink-Warning-%s", str); + lkerr++; + + /* + * Print symbol if symbol based + */ + if (mode & R_SYM) { + fprintf(fptr, " for symbol %s\n", + &s[rindex]->s_id[0]); + } else { + fprintf(fptr, "\n"); + } + + /* + * Print Ref Info + */ + fprintf(fptr, + " file module area offset\n"); + fprintf(fptr, + " Refby %-8.8s %-8.8s %-8.8s ", + hp->h_lfile->f_idp, + &hp->m_id[0], + &a[aindex]->a_bap->a_id[0]); + prntval(fptr, rerr.rtbase); + + /* + * Print Def Info + */ + if (mode & R_SYM) { + raxp = s[rindex]->s_axp; + } else { + raxp = a[rindex]; + } + fprintf(fptr, + " Defin %-8.8s %-8.8s %-8.8s ", + raxp->a_bhp->h_lfile->f_idp, + &raxp->a_bhp->m_id[0], + &raxp->a_bap->a_id[0]); + if (mode & R_SYM) { + prntval(fptr, s[rindex]->s_addr); + } else { + prntval(fptr, rerr.rval); + } +} + +/*)Function VOID prntval(fptr, v) + * + * FILE *fptr output file handle + * Addr_T v value to output + * + * The function prntval() outputs the value v, in the + * currently selected radix, to the device specified + * by fptr. + * + * local variable: + * none + * + * global variables: + * int xflag current radix + * + * called functions: + * int fprintf() c_library + * + * side effects: + * none + * + */ + +VOID +prntval(fptr, v) +FILE *fptr; +Addr_T v; +{ + if (xflag == 0) { + fprintf(fptr, "%04X\n", v); + } else + if (xflag == 1) { + fprintf(fptr, "%06o\n", v); + } else + if (xflag == 2) { + fprintf(fptr, "%05u\n", v); + } +} + +/*)Function VOID relerp(str) + * + * char *str error string + * + * The function relerp() outputs the paging error string to + * stderr and to the map file (if it is open). + * + * local variable: + * none + * + * global variables: + * FILE *mfp handle for the map file + * + * called functions: + * VOID erpdmp() lkrloc.c + * + * side effects: + * Error message inserted into map file. + * + */ + +VOID +relerp(str) +char *str; +{ + erpdmp(stderr, str); + if (mfp) + erpdmp(mfp, str); +} + +/*)Function VOID erpdmp(fptr, str) + * + * FILE *fptr output file handle + * char *str error string + * + * The function erpdmp() outputs the error string str + * to the device specified by fptr. + * + * local variable: + * head *thp pointer to head structure + * + * global variables: + * int lkerr error flag + * sdp sdp base page structure + * + * called functions: + * int fprintf() c_library + * VOID prntval() lkrloc.c + * + * side effects: + * Error reported. + * + */ + +VOID +erpdmp(fptr, str) +FILE *fptr; +char *str; +{ + register struct head *thp; + + thp = sdp.s_areax->a_bhp; + + /* + * Print Error + */ + fprintf(fptr, "\n?ASlink-Warning-%s\n", str); + lkerr++; + + /* + * Print PgDef Info + */ + fprintf(fptr, + " file module pgarea pgoffset\n"); + fprintf(fptr, + " PgDef %-8.8s %-8.8s %-8.8s ", + thp->h_lfile->f_idp, + &thp->m_id[0], + &sdp.s_area->a_id[0]); + prntval(fptr, sdp.s_area->a_addr + sdp.s_addr); +} diff --git a/as/hc08/lks19.c b/as/hc08/lks19.c new file mode 100644 index 00000000..26d8892e --- /dev/null +++ b/as/hc08/lks19.c @@ -0,0 +1,122 @@ +/* lks19.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +#include "aslink.h" + +/*)Module lks19.c + * + * The module lks19.c contains the function to + * output the relocated object code in the + * Motorola S19 format. + * + * lks19.c contains the following function: + * VOID s19(i) + * + * lks19.c contains no local variables. + */ + +/*)S19 Format + * Record Type Field - This field signifies the start of a + * record and identifies the the record + * type as follows: + * + * Ascii S1 - Data Record + * Ascii S9 - End of File Record + * + * Record Length Field - This field specifies the record length + * which includes the address, data, and + * checksum fields. The 8 bit record + * length value is converted to two ascii + * characters, high digit first. + * + * Load Address Field - This field consists of the four ascii + * characters which result from converting + * the the binary value of the address in + * which to begin loading this record. The + * order is as follows: + * + * High digit of high byte of address. + * Low digit of high byte of address. + * High digit of low byte of address. + * Low digit of low byte of address. + * + * In an End of File record this field con- + * sists of either four ascii zeros or the + * program entry address. Currently the + * entry address option is not supported. + * + * Data Field - This field consists of the actual data, + * converted to two ascii characters, high + * digit first. There are no data bytes in + * the End of File record. + * + * Checksum Field - The checksum field is the 8 bit binary + * sum of the record length field, the load + * address field, and the data field. This + * sum is then complemented (1's comple- + * ment) and converted to two ascii + * characters, high digit first. + */ + +/*)Function s19(i) + * + * int i 0 - process data + * 1 - end of data + * + * The function s19() outputs the relocated data + * in the standard Motorola S19 format. + * + * local variables: + * Addr_T chksum byte checksum + * + * global variables: + * int hilo byte order + * FILE * ofp output file handle + * int rtcnt count of data words + * int rtflg[] output the data flag + * Addr_T rtval[] relocated data + * + * functions called: + * int fprintf() c_library + * + * side effects: + * The data is output to the file defined by ofp. + */ + +VOID +s19(i) +{ + register Addr_T chksum; + + if (i) { + if (hilo == 0) { + chksum = rtval[0]; + rtval[0] = rtval[1]; + rtval[1] = chksum; + } + for (i = 0, chksum = 1; i < rtcnt; i++) { + if (rtflg[i]) + chksum++; + } + fprintf(ofp, "S1%02X", chksum); + for (i = 0; i < rtcnt ; i++) { + if (rtflg[i]) { + fprintf(ofp, "%02X", rtval[i]); + chksum += rtval[i]; + } + } + fprintf(ofp, "%02X\n", (0-chksum-1) & 0xff); + } else { + fprintf(ofp, "S9030000FC\n"); + } +} diff --git a/as/hc08/lkstore.c b/as/hc08/lkstore.c new file mode 100644 index 00000000..063e89c4 --- /dev/null +++ b/as/hc08/lkstore.c @@ -0,0 +1,50 @@ +/* lkstore.c */ + +/* + * Allocated string storage module. + * + * 31-Oct-1997 by John Hartman + */ + +#include +#include +#include +#include "aslink.h" + +/* + * Allocate space for "str", copy str into new space + * Return a pointer to the allocated name, or NULL if out of memory + */ +char *StoreString( char *str ) +{ + /* To avoid wasting memory headers on small allocations, we + / allocate a big chunk and parcel it out as required. + / These static variables remember our hunk + */ + #define STR_STORE_HUNK 2000 + static char *pNextFree = NULL; + static int bytesLeft = 0; + + int length; + char *pStoredString; + + length = strlen( str ) + 1; /* what we need, including null */ + + if (length > bytesLeft) + { + /* no space. Allocate a new hunk. We lose the pointer to any + / old hunk. We don't care, as the names are never deleted. + */ + pNextFree = (char*)new( STR_STORE_HUNK ); + bytesLeft = STR_STORE_HUNK; + } + + /* Copy the name and terminating null into the name store */ + pStoredString = pNextFree; + memcpy( pStoredString, str, length ); + + pNextFree += length; + bytesLeft -= length; + + return pStoredString; +} diff --git a/as/hc08/lksym.c b/as/hc08/lksym.c new file mode 100644 index 00000000..1ebc49cc --- /dev/null +++ b/as/hc08/lksym.c @@ -0,0 +1,488 @@ +/* lksym.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + * + * 28-Oct-97 JLH: + * - lkpsym: Use StoreString for sym construction + * - change symeq() to do length-independent string compare + * - change hash() to do length-independent hash calculation + */ + +#include +#include +#if defined(_MSC_VER) +#include +#else +#include +#endif +#include "aslink.h" + +/*)Module lksym.c + * + * The module lksym.c contains the functions that operate + * on the symbol structures. + * + * lksym.c contains the following functions: + * int hash() + * sym * lkpsym() + * VOID * new() + * sym * newsym() + * VOID symdef() + * int symeq() + * VOID syminit() + * VOID symmod() + * Addr_T symval() + * + * lksym.c contains no local/static variables. + */ + +/*)Function VOID syminit() + * + * The function syminit() is called to clear the hashtable. + * + * local variables: + * int h computed hash value + * sym ** spp pointer to an array of + * sym structure pointers + * + * global variables: + * sym * symhash[] array of pointers to NHASH + * linked symbol lists + * + * functions called: + * none + * + * side effects: + * (1) The symbol hash tables are cleared + */ + +VOID +syminit() +{ + // register int h; + struct sym **spp; + + spp = &symhash[0]; + while (spp < &symhash[NHASH]) + *spp++ = NULL; +} + +/*)Function sym * newsym() + * + * The function newsym() is called to evaluate the symbol + * definition/reference directive from the .rel file(s). + * If the symbol is not found in the symbol table a new + * symbol structure is created. Evaluation of the + * directive determines if this is a reference or a definition. + * Multiple definitions of the same variable will be flagged + * as an error if the values are not identical. A symbol + * definition places the symbol value and area extension + * into the symbols data structure. And finally, a pointer + * to the symbol structure is placed into the head structure + * symbol list. Refer to the description of the header, symbol, + * area, and areax structures in lkdata.c for structure and + * linkage details. + * + * local variables: + * int c character from input text + * int i evaluation value + * char id[] symbol name + * int nglob number of symbols in this header + * sym * tsp pointer to symbol structure + * sym ** s list of pointers to symbol structures + * + * global variables: + * areax *axp Pointer to the current + * areax structure + * head *headp The pointer to the first + * head structure of a linked list + * int lkerr error flag + * + * functions called: + * Addr_T eval() lkeval.c + * VOID exit() c_library + * int fprintf() c_library + * char getSid() lklex.c + * char get() lklex.c + * char getnb() lklex.c + * sym * lkpsym() lksym.c + * + * side effects: + * A symbol structure is created and/or modified. + * If structure space allocation fails linker will abort. + * Several severe errors (these are internal errors + * indicating a corrupted .rel file or corrupted + * assembler or linker) will terminated the linker. + */ + +/* + * Find/Create a global symbol entry. + * + * S xxxxxx Defnnnn + * | | | + * | | `-- sp->s_addr + * | `----- sp->s_type + * `------------ sp->s_id + * + */ +struct sym * +newsym() +{ + register unsigned i ; + register unsigned nglob ; + register int c ; + struct sym *tsp; + struct sym **s; + char id[NCPS]; + + getSid(id); // old: getid(id, -1); + tsp = lkpsym(id, 1); + c = getnb();get();get(); + if (c == 'R') { + tsp->s_type |= S_REF; + if (eval()) { + fprintf(stderr, "Non zero S_REF\n"); + lkerr++; + } + } else + if (c == 'D') { + i = eval(); + if (tsp->s_type & S_DEF && tsp->s_addr != i) { + fprintf(stderr, "Multiple definition of %8s\n", id); + lkerr++; + } + tsp->s_type |= S_DEF; + /* + * Set value and area extension link. + */ + tsp->s_addr = i; + tsp->s_axp = axp; + } else { + fprintf(stderr, "Invalid symbol type %c for %8s\n", c, id); + lkexit(1); + } + /* + * Place pointer in header symbol list + */ + if (headp == NULL) { + fprintf(stderr, "No header defined\n"); + lkexit(1); + } + nglob = hp->h_nglob; + s = hp->s_list; + for (i=0; i < nglob ;++i) { + if (s[i] == NULL) { + s[i] = tsp; + return(tsp); + } + } + fprintf(stderr, "Header symbol list overflow\n"); + lkexit(1); + return(0); +} + +/*)Function sym * lkpsym(id,f) + * + * char * id symbol name string + * int f f == 0, lookup only + * f != 0, create if not found + * + * The function lookup() searches the symbol hash tables for + * a symbol name match returning a pointer to the sym structure. + * If the symbol is not found then a sym structure is created, + * initialized, and linked to the appropriate hash table if f != 0. + * A pointer to this new sym structure is returned or a NULL + * pointer is returned if f == 0. + * + * local variables: + * int h computed hash value + * sym * sp pointer to a sym structure + * + * global varaibles: + * sym * symhash[] array of pointers to NHASH + * linked symbol lists + * + * functions called: + * int hash() lksym.c + * VOID * new() lksym.c + * int symeq() lksym.c + * + * side effects: + * If the function new() fails to allocate space + * for the new sym structure the linker terminates. + */ + +struct sym * +lkpsym(id, f) +char *id; +{ + register struct sym *sp; + register int h; + + h = hash(id); + sp = symhash[h]; + while (sp != NULL) { + if (symeq(id, sp->s_id)) + return (sp); + sp = sp->s_sp; + } + if (f == 0) + return (NULL); + sp = (struct sym *) new (sizeof(struct sym)); + sp->s_sp = symhash[h]; + symhash[h] = sp; + sp->s_id = StoreString( id ); /* JLH */ + return (sp); +} + +/*)Function Addr_T symval(tsp) + * + * sym * tsp pointer to a symbol structure + * + * The function symval() returns the value of the + * relocated symbol by adding the variable definition + * value to the areax base address. + * + * local variables: + * Addr_T val relocated address value + * + * global variables: + * none + * + * functions called: + * none + * + * side effects: + * none + */ + +Addr_T +symval(tsp) +register struct sym *tsp; +{ + register Addr_T val; + + val = tsp->s_addr; + if (tsp->s_axp) { + val += tsp->s_axp->a_addr; + } + return(val); +} + +/*)Function VOID symdef(fp) + * + * FILE * fp file handle for output + * + * The function symdef() scans the hashed symbol table + * searching for variables referenced but not defined. + * Undefined variables are linked to the default + * area "_CODE" and reported as referenced by the + * appropriate module. + * + * local variables: + * int i hash table index loop variable + * sym * sp pointer to linked symbol structure + * + * global variables: + * area *areap The pointer to the first + * area structure of a linked list + * sym *symhash[NHASH] array of pointers to NHASH + * linked symbol lists + * + * functions called: + * symmod() lksym.c + * + * side effects: + * Undefined variables have their areas set to "_CODE". + */ + +VOID +symdef(fp) +FILE *fp; +{ + register struct sym *sp; + register int i; + + for (i=0; is_axp == NULL) + sp->s_axp = areap->a_axp; + if ((sp->s_type & S_DEF) == 0) + symmod(fp, sp); + sp = sp->s_sp; + } + } +} + +/*)Function VOID symmod(fp,tsp) + * + * FILE * fp output file handle + * sym * tsp pointer to a symbol structure + * + * The function symmod() scans the header structures + * searching for a reference to the symbol structure + * pointer to by tsp. The function then generates an error + * message whichs names the module having referenced the + * undefined variable. + * + * local variables: + * int i loop counter + * sym ** p pointer to a list of pointers + * to symbol structures + * + * global variables: + * head *headp The pointer to the first + * head structure of a linked list + * head *hp Pointer to the current + * head structure + * int lkerr error flag + * + * functions called: + * int fprintf() c_library + * + * side effects: + * Error output generated. + */ + +VOID +symmod(fp, tsp) +FILE *fp; +struct sym *tsp; +{ + register int i; + struct sym **p; + + if ((hp = headp) != NULL) { + while(hp) { + p = hp->s_list; + for (i=0; ih_nglob; ++i) { + if (p[i] == tsp) { + fprintf(fp, "\n?ASlink-Warning-Undefined Global '%s' ", tsp->s_id); + fprintf(fp, "referenced by module '%s'\n", hp->m_id); + lkerr++; + } + } + hp = hp->h_hp; + } + } +} + +/*)Function int symeq(p1, p2) + * + * char * p1 name string + * char * p2 name string + * + * The function symeq() compares the two name strings for a match. + * The return value is 1 for a match and 0 for no match. + * + * local variables: + * int h loop counter + * + * global variables: + * char ccase[] an array of characters which + * perform the case translation function + * + * functions called: + * none + * + * side effects: + * none + * + */ + +int +symeq(p1, p2) +register char *p1, *p2; +{ +#if CASE_SENSITIVE + return (strcmp( p1, p2 ) == 0); +#else + return (as_strcmpi( p1, p2 ) == 0); +#endif +} + +/*)Function int hash(p) + * + * char * p pointer to string to hash + * + * The function hash() computes a hash code using the sum + * of all characters mod table size algorithm. + * + * local variables: + * int h accumulated character sum + * int n loop counter + * + * global variables: + * char ccase[] an array of characters which + * perform the case translation function + * + * functions called: + * none + * + * side effects: + * none + * + */ + +int +hash(p) +register char *p; +{ + register int h; + + h = 0; + while (*p) { + +#if CASE_SENSITIVE + h += *p++; +#else + h += ccase[*p++]; +#endif + + }; + return (h&HMASK); +} + +/*)Function VOID * new(n) + * + * unsigned int n allocation size in bytes + * + * The function new() allocates n bytes of space and returns + * a pointer to this memory. If no space is available the + * linker is terminated. + * + * local variables: + * char * p a general pointer + * char * q a general pointer + * + * global variables: + * none + * + * functions called: + * int fprintf() c_library + * VOID * malloc() c_library + * + * side effects: + * Memory is allocated, if allocation fails + * the linker is terminated. + */ + +VOID * +new(n) +unsigned int n; +{ + register char *p; + + if ((p = (char *) calloc(n, 1)) == NULL) { + fprintf(stderr, "Out of space!\n"); + lkexit(1); + } + return (p); +} diff --git a/as/hc08/m08adr.c b/as/hc08/m08adr.c new file mode 100644 index 00000000..61e10b4c --- /dev/null +++ b/as/hc08/m08adr.c @@ -0,0 +1,205 @@ +/* m08adr.c */ + +/* + * (C) Copyright 1993-2002 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +#include "asm.h" +#include "m6808.h" + +int +addr(esp) +register struct expr *esp; +{ + register int c; + register struct area *espa; + register Addr_T espv; + char *tcp; + + if ((c = getnb()) == '#') { + expr(esp, 0); + esp->e_mode = S_IMMED; + } else if (c == ',') { + switch(admode(axs)) { + default: + aerr(); + + case S_X: + c = S_IX; + break; + + case S_S: + c = S_IS; + break; + + case S_XP: + c = S_IXP; + break; + } + esp->e_mode = c; + } else if (c == '*') { + expr(esp, 0); + esp->e_mode = S_DIR; + if (esp->e_addr & ~0xFF) + err('d'); + if (more()) { + comma(); + tcp = ip; + switch(admode(axs)) { + case S_X: + esp->e_mode = S_IX1; + break; + + case S_S: + esp->e_mode = S_SP1; + break; + + case S_XP: + esp->e_mode = S_IX1P; + break; + + default: + ip = --tcp; + } + } + } else { + unget(c); + if ((esp->e_mode = admode(axs)) != 0) { + ; + } else { + expr(esp, 0); + espa = esp->e_base.e_ap; + espv = esp->e_addr; + if (more()) { + comma(); + c = admode(axs); + if (esp->e_flag == 0 && + espa == NULL && + (espv & ~0xFF) == 0) { + switch(c) { + default: + aerr(); + + case S_X: + c = S_IX1; + break; + + case S_S: + c = S_SP1; + break; + + case S_XP: + c = S_IX1P; + break; + } + } else { + switch(c) { + default: + aerr(); + + case S_X: + c = S_IX2; + break; + + case S_S: + c = S_SP2; + break; + + case S_XP: + c = S_IX2P; + break; + } + } + esp->e_mode = c; + } else { + esp->e_mode = S_EXT; + } + } + } + return (esp->e_mode); +} + +/* + * Enter admode() to search a specific addressing mode table + * for a match. Return the addressing value on a match or + * zero for no match. + */ +int +admode(sp) +register struct adsym *sp; +{ + register char *ptr; + register int i; + register char *ips; + + ips = ip; + unget(getnb()); + + i = 0; + while ( *(ptr = &sp[i].a_str[0]) ) { + if (srch(ptr)) { + return(sp[i].a_val); + } + i++; + } + ip = ips; + return(0); +} + +/* + * srch --- does string match ? + */ +int +srch(str) +register char *str; +{ + register char *ptr; + ptr = ip; + + while (*ptr && *str) { + if(ccase[*ptr & 0x007F] != ccase[*str & 0x007F]) + break; + ptr++; + str++; + } + if (ccase[*ptr & 0x007F] == ccase[*str & 0x007F]) { + ip = ptr; + return(1); + } + + if (!*str) + if (any(*ptr," \t\n,];")) { + ip = ptr; + return(1); + } + return(0); +} + +/* + * any --- does str contain c? + */ +int +any(c,str) +int c; +char*str; +{ + while (*str) + if(*str++ == c) + return(1); + return(0); +} + +struct adsym axs[] = { /* a, x, or s registers */ + { "a", S_A }, + { "x", S_X }, + { "s", S_S }, + { "x+", S_XP }, + { "", 0x00 } +}; diff --git a/as/hc08/m08ext.c b/as/hc08/m08ext.c new file mode 100644 index 00000000..88247315 --- /dev/null +++ b/as/hc08/m08ext.c @@ -0,0 +1,19 @@ +/* m08ext.c */ + +/* + * (C) Copyright 1993-2002 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +#include "asm.h" +#include "m6808.h" + +char *cpu = "Motorola 68HC08"; +int hilo = 1; +char *dsft = "asm"; diff --git a/as/hc08/m08mch.c b/as/hc08/m08mch.c new file mode 100644 index 00000000..5c54496b --- /dev/null +++ b/as/hc08/m08mch.c @@ -0,0 +1,463 @@ +/* m08mch.c */ + +/* + * (C) Copyright 1993-2002 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +#include "asm.h" +#include "m6808.h" + +/* + * Process a machine op. + */ +VOID +machine(mp) +struct mne *mp; +{ + register int op, t1, t2, type; + struct expr e1, e2, e3; + Addr_T espv; + struct area *espa; + char id[NCPS]; + int c, v1; + + clrexpr(&e1); + clrexpr(&e2); + clrexpr(&e3); + op = mp->m_valu; + type = mp->m_type; + switch (type) { + + case S_SDP: + espa = NULL; + if (more()) { + expr(&e1, 0); + if (e1.e_flag == 0 && e1.e_base.e_ap == NULL) { + if (e1.e_addr) { + err('b'); + } + } + if ((c = getnb()) == ',') { + getid(id, -1); + espa = alookup(id); + if (espa == NULL) { + err('u'); + } + } else { + unget(c); + } + } + if (espa) { + outdp(espa, &e1); + } else { + outdp(dot.s_area, &e1); + } + lmode = SLIST; + break; + + case S_INH: + outab(op); + break; + + case S_BRA: + expr(&e1, 0); + outab(op); + if (mchpcr(&e1)) { + v1 = e1.e_addr - dot.s_addr - 1; + if ((v1 < -128) || (v1 > 127)) + aerr(); + outab(v1); + } else { + outrb(&e1, R_PCR); + } + if (e1.e_mode != S_USER) + rerr(); + break; + + case S_TYP1: + t1 = addr(&e1); + if (t1 == S_A) { + outab(op+0x10); + break; + } + if (t1 == S_X) { + outab(op+0x20); + break; + } + if (t1 == S_DIR || t1 == S_EXT) { + outab(op); + outrb(&e1, R_PAG0); + break; + } + if (t1 == S_IX) { + outab(op+0x40); + break; + } + if (t1 == S_IX1 || t1 == S_IX2) { + if (chkindx(&e1)) + aerr(); + outab(op+0x30); + outrb(&e1, R_USGN); + break; + } + if (t1 == S_SP1 || t1 == S_SP2) { + if (chkindx(&e1)) + aerr(); + outab(0x9e); + outab(op+0x30); + outrb(&e1, R_USGN); + break; + } + aerr(); + break; + + case S_TYP2: + t1 = addr(&e1); + if (t1 == S_IMMED) { + if ((op == 0xA7) || (op == 0xAC) || + (op == 0xAD) || (op == 0xAF)) + aerr(); + outab(op); + outrb(&e1, 0); + break; + } + if (t1 == S_DIR) { + outab(op+0x10); + outrb(&e1, R_PAG0); + break; + } + if (t1 == S_EXT) { + outab(op+0x20); + outrw(&e1, 0); + break; + } + if (t1 == S_IX) { + outab(op+0x50); + break; + } + if (t1 == S_IX1) { + outab(op+0x40); + outrb(&e1, R_USGN); + break; + } + if (t1 == S_IX2) { + outab(op+0x30); + outrw(&e1, 0); + break; + } + if (t1 == S_SP1) { + if (op == 0xAC || op == 0xAD) + aerr(); + outab(0x9e); + outab(op+0x40); + outrb(&e1, R_USGN); + break; + } + if (t1 == S_SP2) { + if (op == 0xAC || op == 0xAD) + aerr(); + outab(0x9e); + outab(op+0x30); + outrw(&e1, 0); + break; + } + aerr(); + break; + + case S_TYP3: + t1 = addr(&e1); + espv = e1.e_addr; + if (t1 != S_IMMED || espv & ~0x07) + aerr(); + comma(); + t2 = addr(&e2); + if (t2 != S_DIR) + aerr(); + outab(op + 2*(espv&0x07)); + outrb(&e2, R_PAG0); + break; + + case S_TYP4: + t1 = addr(&e1); + espv = e1.e_addr; + if (t1 != S_IMMED || espv & ~0x07) + aerr(); + comma(); + t2 = addr(&e2); + if (t2 != S_DIR) + aerr(); + comma(); + expr(&e3, 0); + outab(op + 2*(espv&0x07)); + outrb(&e2, R_PAG0); + if (mchpcr(&e3)) { + v1 = e3.e_addr - dot.s_addr - 1; + if ((v1 < -128) || (v1 > 127)) + aerr(); + outab(v1); + } else { + outrb(&e3, R_PCR); + } + if (e3.e_mode != S_USER) + rerr(); + break; + + case S_TYPAI: + t1 = addr(&e1); + if (t1 == S_IMMED) { + outab(op); + if (e1.e_flag == 0 && e1.e_base.e_ap == NULL) { + v1 = e1.e_addr; + if ((v1 < -128) || (v1 > 127)) + aerr(); + outab(v1); + } else { + outrb(&e1, 0); + } + break; + } + aerr(); + break; + + case S_TYPHX: + t1 = addr(&e1); + if (t1 == S_IMMED) { + if (op == 0x25) + aerr(); + outab(op); + outrw(&e1, 0); + break; + } + if (t1 == S_DIR || t1 == S_EXT) { + outab(op | 0x10); + outrb(&e1, R_PAG0); + break; + } + aerr(); + break; + + case S_CBEQ: + t1 = addr(&e1); + comma(); + expr(&e2, 0); + if (t1 == S_IMMED) { + outab(op); + outrb(&e1, 0); + } else + if (t1 == S_DIR || t1 == S_EXT) { + outab(op); + outrb(&e1, R_PAG0); + } else + if (t1 == S_IXP) { + outab(op+0x40); + } else + if (t1 == S_IX1P || t1 == S_IX2P) { + if (chkindx(&e1)) + aerr(); + outab(op+0x30); + outrb(&e1, R_USGN); + } else + if (t1 == S_SP1 || t1 == S_SP2) { + if (chkindx(&e1)) + aerr(); + outab(0x9E); + outab(op+0x30); + outrb(&e1, R_USGN); + } else { + aerr(); + break; + } + if (mchpcr(&e2)) { + v1 = e2.e_addr - dot.s_addr - 1; + if ((v1 < -128) || (v1 > 127)) + aerr(); + outab(v1); + } else { + outrb(&e2, R_PCR); + } + if (e2.e_mode != S_USER) + rerr(); + break; + + case S_CQAX: + t1 = addr(&e1); + if (t1 != S_IMMED) + aerr(); + comma(); + expr(&e2, 0); + outab(op); + outrb(&e1, 0); + if (mchpcr(&e2)) { + v1 = e2.e_addr - dot.s_addr - 1; + if ((v1 < -128) || (v1 > 127)) + aerr(); + outab(v1); + } else { + outrb(&e2, R_PCR); + } + if (e2.e_mode != S_USER) + rerr(); + break; + + case S_DBNZ: + t1 = addr(&e1); + comma(); + expr(&e2, 0); + if (t1 == S_DIR || t1 == S_EXT) { + outab(op); + outrb(&e1, R_PAG0); + } else + if (t1 == S_IX) { + outab(op+0x40); + } else + if (t1 == S_IX1 || t1 == S_IX2) { + if (chkindx(&e1)) + aerr(); + outab(op+0x30); + outrb(&e1, R_USGN); + } else + if (t1 == S_SP1 || t1 == S_SP2) { + if (chkindx(&e1)) + aerr(); + outab(0x9E); + outab(op+0x30); + outrb(&e1, R_USGN); + } else { + aerr(); + break; + } + if (mchpcr(&e2)) { + v1 = e2.e_addr - dot.s_addr - 1; + if ((v1 < -128) || (v1 > 127)) + aerr(); + outab(v1); + } else { + outrb(&e2, R_PCR); + } + if (e2.e_mode != S_USER) + rerr(); + break; + + case S_DZAX: + expr(&e1, 0); + outab(op); + if (mchpcr(&e1)) { + v1 = e1.e_addr - dot.s_addr - 1; + if ((v1 < -128) || (v1 > 127)) + aerr(); + outab(v1); + } else { + outrb(&e1, R_PCR); + } + if (e1.e_mode != S_USER) + rerr(); + break; + + case S_MOV: + t1 = addr(&e1); + if (t1 == S_IX1P || t1 == S_IX2P) { + if (chkindx(&e1)) + aerr(); + outab(op+0x10); + outrb(&e1, R_PAG0); + break; + } + comma(); + t2 = addr(&e2); + if (t1 == S_IMMED) { + if (t2 == S_DIR || t2 == S_EXT) { + outab(op+0x20); + outrb(&e1, 0); + outrb(&e2, R_PAG0); + break; + } + } + if (t1 == S_DIR || t1 == S_EXT) { + if (t2 == S_DIR || t2 == S_EXT) { + outab(op); + outrb(&e1, R_PAG0); + outrb(&e2, R_PAG0); + break; + } + } + if (t1 == S_IXP) { + if (t2 == S_DIR || t2 == S_EXT) { + outab(op+0x30); + outrb(&e2, R_PAG0); + break; + } + } + aerr(); + break; + + default: + err('o'); + } +} + +/* + * Check index byte + */ +int +chkindx(exp) +struct expr *exp; +{ + if (exp->e_flag == 0 && exp->e_base.e_ap == NULL) { + if (exp->e_addr & ~0xFF) { + return(1); + } + } + return(0); +} + +/* + * Branch/Jump PCR Mode Check + */ +int +mchpcr(esp) +register struct expr *esp; +{ + if (esp->e_base.e_ap == dot.s_area) { + return(1); + } + if (esp->e_flag==0 && esp->e_base.e_ap==NULL) { + /* + * Absolute Destination + * + * Use the global symbol '.__.ABS.' + * of value zero and force the assembler + * to use this absolute constant as the + * base value for the relocation. + */ + esp->e_flag = 1; + esp->e_base.e_sp = &sym[1]; + } + return(0); +} + +/* + * The next character must be a + * comma. + */ +int +comma() +{ + if (getnb() != ',') + qerr(); + return(1); +} + +/* + * Machine specific initialization. + */ +VOID +minit() +{ +} diff --git a/as/hc08/m08pst.c b/as/hc08/m08pst.c new file mode 100644 index 00000000..54d725e8 --- /dev/null +++ b/as/hc08/m08pst.c @@ -0,0 +1,195 @@ +/* m08pst.c */ + +/* + * (C) Copyright 1993-2002 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +#include "asm.h" +#include "m6808.h" + +struct mne mne[] = { + + /* machine */ + + { NULL, ".setdp", S_SDP, 0, 0 }, + + /* system */ + + { NULL, "CON", S_ATYP, 0, A_CON }, + { NULL, "OVR", S_ATYP, 0, A_OVR }, + { NULL, "REL", S_ATYP, 0, A_REL }, + { NULL, "ABS", S_ATYP, 0, A_ABS|A_OVR }, + { NULL, "NOPAG", S_ATYP, 0, A_NOPAG }, + { NULL, "PAG", S_ATYP, 0, A_PAG }, + + { NULL, ".byte", S_BYTE, 0, 1 }, + { NULL, ".db", S_BYTE, 0, 1 }, + { NULL, ".word", S_WORD, 0, 2 }, + { NULL, ".dw", S_WORD, 0, 2 }, + { NULL, ".ascii", S_ASCII, 0, 0 }, + { NULL, ".asciz", S_ASCIZ, 0, 0 }, + { NULL, ".blkb", S_BLK, 0, 1 }, + { NULL, ".ds", S_BLK, 0, 1 }, + { NULL, ".blkw", S_BLK, 0, 2 }, + { NULL, ".page", S_PAGE, 0, 0 }, + { NULL, ".title", S_TITLE, 0, 0 }, + { NULL, ".sbttl", S_SBTL, 0, 0 }, + { NULL, ".globl", S_GLOBL, 0, 0 }, + { NULL, ".area", S_DAREA, 0, 0 }, + { NULL, ".even", S_EVEN, 0, 0 }, + { NULL, ".odd", S_ODD, 0, 0 }, + { NULL, ".if", S_IF, 0, 0 }, + { NULL, ".else", S_ELSE, 0, 0 }, + { NULL, ".endif", S_ENDIF, 0, 0 }, + { NULL, ".include", S_INCL, 0, 0 }, + { NULL, ".radix", S_RADIX, 0, 0 }, + { NULL, ".org", S_ORG, 0, 0 }, + { NULL, ".module", S_MODUL, 0, 0 }, + { NULL, ".ascis", S_ASCIS, 0, 0 }, +// { NULL, ".assume", S_ERROR, 0, 0 }, +// { NULL, ".error", S_ERROR, 0, 1 }, + + /* 68HC08 */ + + { NULL, "neg", S_TYP1, 0, 0x30 }, + { NULL, "com", S_TYP1, 0, 0x33 }, + { NULL, "lsr", S_TYP1, 0, 0x34 }, + { NULL, "ror", S_TYP1, 0, 0x36 }, + { NULL, "asr", S_TYP1, 0, 0x37 }, + { NULL, "asl", S_TYP1, 0, 0x38 }, + { NULL, "lsl", S_TYP1, 0, 0x38 }, + { NULL, "rol", S_TYP1, 0, 0x39 }, + { NULL, "dec", S_TYP1, 0, 0x3A }, + { NULL, "inc", S_TYP1, 0, 0x3C }, + { NULL, "tst", S_TYP1, 0, 0x3D }, + { NULL, "clr", S_TYP1, 0, 0x3F }, + + { NULL, "sub", S_TYP2, 0, 0xA0 }, + { NULL, "cmp", S_TYP2, 0, 0xA1 }, + { NULL, "sbc", S_TYP2, 0, 0xA2 }, + { NULL, "cpx", S_TYP2, 0, 0xA3 }, + { NULL, "and", S_TYP2, 0, 0xA4 }, + { NULL, "bit", S_TYP2, 0, 0xA5 }, + { NULL, "lda", S_TYP2, 0, 0xA6 }, + { NULL, "sta", S_TYP2, 0, 0xA7 }, + { NULL, "eor", S_TYP2, 0, 0xA8 }, + { NULL, "adc", S_TYP2, 0, 0xA9 }, + { NULL, "ora", S_TYP2, 0, 0xAA }, + { NULL, "add", S_TYP2, 0, 0xAB }, + { NULL, "jmp", S_TYP2, 0, 0xAC }, + { NULL, "jsr", S_TYP2, 0, 0xAD }, + { NULL, "ldx", S_TYP2, 0, 0xAE }, + { NULL, "stx", S_TYP2, 0, 0xAF }, + + { NULL, "bset", S_TYP3, 0, 0x10 }, + { NULL, "bclr", S_TYP3, 0, 0x11 }, + + { NULL, "brset", S_TYP4, 0, 0x00 }, + { NULL, "brclr", S_TYP4, 0, 0x01 }, + + { NULL, "ais", S_TYPAI, 0, 0xA7 }, + { NULL, "aix", S_TYPAI, 0, 0xAF }, + + { NULL, "sthx", S_TYPHX, 0, 0x25 }, + { NULL, "ldhx", S_TYPHX, 0, 0x45 }, + { NULL, "cphx", S_TYPHX, 0, 0x65 }, + + { NULL, "cbeq", S_CBEQ, 0, 0x31 }, + { NULL, "cbeqa", S_CQAX, 0, 0x41 }, + { NULL, "cbeqx", S_CQAX, 0, 0x51 }, + + { NULL, "dbnz", S_DBNZ, 0, 0x3B }, + { NULL, "dbnza", S_DZAX, 0, 0x4B }, + { NULL, "dbnzx", S_DZAX, 0, 0x5B }, + + { NULL, "mov", S_MOV, 0, 0x4E }, + + { NULL, "bra", S_BRA, 0, 0x20 }, + { NULL, "brn", S_BRA, 0, 0x21 }, + { NULL, "bhi", S_BRA, 0, 0x22 }, + { NULL, "bls", S_BRA, 0, 0x23 }, + { NULL, "bcc", S_BRA, 0, 0x24 }, + { NULL, "bhs", S_BRA, 0, 0x24 }, + { NULL, "bcs", S_BRA, 0, 0x25 }, + { NULL, "blo", S_BRA, 0, 0x25 }, + { NULL, "bne", S_BRA, 0, 0x26 }, + { NULL, "beq", S_BRA, 0, 0x27 }, + { NULL, "bhcc", S_BRA, 0, 0x28 }, + { NULL, "bhcs", S_BRA, 0, 0x29 }, + { NULL, "bpl", S_BRA, 0, 0x2A }, + { NULL, "bmi", S_BRA, 0, 0x2B }, + { NULL, "bmc", S_BRA, 0, 0x2C }, + { NULL, "bms", S_BRA, 0, 0x2D }, + { NULL, "bil", S_BRA, 0, 0x2E }, + { NULL, "bih", S_BRA, 0, 0x2F }, + { NULL, "bge", S_BRA, 0, 0x90 }, + { NULL, "blt", S_BRA, 0, 0x91 }, + { NULL, "bgt", S_BRA, 0, 0x92 }, + { NULL, "ble", S_BRA, 0, 0x93 }, + { NULL, "bsr", S_BRA, 0, 0xAD }, + + { NULL, "nega", S_INH, 0, 0x40 }, + { NULL, "mul", S_INH, 0, 0x42 }, + { NULL, "coma", S_INH, 0, 0x43 }, + { NULL, "lsra", S_INH, 0, 0x44 }, + { NULL, "rora", S_INH, 0, 0x46 }, + { NULL, "asra", S_INH, 0, 0x47 }, + { NULL, "asla", S_INH, 0, 0x48 }, + { NULL, "lsla", S_INH, 0, 0x48 }, + { NULL, "rola", S_INH, 0, 0x49 }, + { NULL, "deca", S_INH, 0, 0x4A }, + { NULL, "inca", S_INH, 0, 0x4C }, + { NULL, "tsta", S_INH, 0, 0x4D }, + { NULL, "clra", S_INH, 0, 0x4F }, + + { NULL, "negx", S_INH, 0, 0x50 }, + { NULL, "div", S_INH, 0, 0x52 }, + { NULL, "comx", S_INH, 0, 0x53 }, + { NULL, "lsrx", S_INH, 0, 0x54 }, + { NULL, "rorx", S_INH, 0, 0x56 }, + { NULL, "asrx", S_INH, 0, 0x57 }, + { NULL, "aslx", S_INH, 0, 0x58 }, + { NULL, "lslx", S_INH, 0, 0x58 }, + { NULL, "rolx", S_INH, 0, 0x59 }, + { NULL, "decx", S_INH, 0, 0x5A }, + { NULL, "incx", S_INH, 0, 0x5C }, + { NULL, "tstx", S_INH, 0, 0x5D }, + { NULL, "clrx", S_INH, 0, 0x5F }, + + { NULL, "nsa", S_INH, 0, 0x62 }, + + { NULL, "daa", S_INH, 0, 0x72 }, + + { NULL, "rti", S_INH, 0, 0x80 }, + { NULL, "rts", S_INH, 0, 0x81 }, + { NULL, "swi", S_INH, 0, 0x83 }, + { NULL, "tap", S_INH, 0, 0x84 }, + { NULL, "tpa", S_INH, 0, 0x85 }, + { NULL, "pula", S_INH, 0, 0x86 }, + { NULL, "psha", S_INH, 0, 0x87 }, + { NULL, "pulx", S_INH, 0, 0x88 }, + { NULL, "pshx", S_INH, 0, 0x89 }, + { NULL, "pulh", S_INH, 0, 0x8A }, + { NULL, "pshh", S_INH, 0, 0x8B }, + { NULL, "clrh", S_INH, 0, 0x8C }, + { NULL, "stop", S_INH, 0, 0x8E }, + { NULL, "wait", S_INH, 0, 0x8F }, + + { NULL, "txs", S_INH, 0, 0x94 }, + { NULL, "tsx", S_INH, 0, 0x95 }, + { NULL, "tax", S_INH, 0, 0x97 }, + { NULL, "clc", S_INH, 0, 0x98 }, + { NULL, "sec", S_INH, 0, 0x99 }, + { NULL, "cli", S_INH, 0, 0x9A }, + { NULL, "sei", S_INH, 0, 0x9B }, + { NULL, "rsp", S_INH, 0, 0x9C }, + { NULL, "nop", S_INH, 0, 0x9D }, + { NULL, "txa", S_INH, S_END, 0x9F } +}; diff --git a/as/hc08/m6808.h b/as/hc08/m6808.h new file mode 100644 index 00000000..89929a4a --- /dev/null +++ b/as/hc08/m6808.h @@ -0,0 +1,119 @@ +/* m6808.h */ + +/* + * (C) Copyright 1993-2002 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +/*)BUILD + $(PROGRAM) = AS6808 + $(INCLUDE) = { + ASM.H + M6808.H + } + $(FILES) = { + M08EXT.C + M08MCH.C + M08ADR.C + M08PST.C + ASMAIN.C + ASLEX.C + ASSYM.C + ASSUBR.C + ASEXPR.C + ASDATA.C + ASLIST.C + ASOUT.C + } + $(STACK) = 3000 +*/ + +struct adsym +{ + char a_str[4]; /* addressing string */ + int a_val; /* addressing mode value */ +}; + +/* + * Addressing types + */ +#define S_IMMED 30 +#define S_DIR 31 +#define S_EXT 32 +#define S_IX 33 +#define S_IXP 34 +#define S_IX1 35 +#define S_IX1P 36 +#define S_IX2 37 +#define S_IX2P 38 +#define S_IS 39 +#define S_SP1 40 +#define S_SP2 41 +#define S_A 42 +#define S_X 43 +#define S_S 44 +#define S_XP 45 + +/* + * Instruction types + */ +#define S_INH 60 +#define S_BRA 61 +#define S_TYP1 62 +#define S_TYP2 63 +#define S_TYP3 64 +#define S_TYP4 65 +#define S_TYPAI 66 +#define S_TYPHX 67 +#define S_CBEQ 68 +#define S_CQAX 69 +#define S_DBNZ 70 +#define S_DZAX 71 +#define S_MOV 72 + +/* + * Set Direct Pointer + */ +#define S_SDP 80 + + + /* machine dependent functions */ + +#ifdef OTHERSYSTEM + + /* m08adr.c */ +extern struct adsym axs[]; +extern int addr(struct expr *esp); +extern int admode(struct adsym *sp); +extern int any(int c, char *str); +extern int srch(char *str); + + /* m08mch.c */ +extern VOID machine(struct mne *mp); +extern int chkindx(struct expr *exp); +extern int mchpcr(struct expr *esp); +extern VOID minit(void); +extern int comma(void); + +#else + + /* m08adr.c */ +extern struct adsym axs[]; +extern int addr(); +extern int admode(); +extern int any(); +extern int srch(); + + /* m08mch.c */ +extern VOID machine(); +extern int chkindx(); +extern int mchpcr(); +extern VOID minit(); +extern int comma(); + +#endif + diff --git a/as/hc08/strcmpi.c b/as/hc08/strcmpi.c new file mode 100644 index 00000000..434529ce --- /dev/null +++ b/as/hc08/strcmpi.c @@ -0,0 +1,35 @@ +/* strcmpi.c */ + +/* + * Compare two strings ignoring case. + * + * Taken from GLIBC 2.2.5. Original code is copyrighted "Free + * Software Foundation" and published under the GNU Lesser General + * Public License. + * + */ + +#include +#include "strcmpi.h" + +int as_strcmpi (const char *s1, const char *s2) +{ + const unsigned char *p1 = (const unsigned char *) s1; + const unsigned char *p2 = (const unsigned char *) s2; + unsigned char c1, c2; + + if (p1 == p2) + return 0; + + do + { + c1 = tolower (*p1++); + c2 = tolower (*p2++); + if (c1 == '\0') + break; + } + while (c1 == c2); + + return c1 - c2; +} + diff --git a/as/hc08/strcmpi.h b/as/hc08/strcmpi.h new file mode 100644 index 00000000..63c35c43 --- /dev/null +++ b/as/hc08/strcmpi.h @@ -0,0 +1,3 @@ +/* strcmpi.h */ + +int as_strcmpi (const char *s1, const char *s2);