1 /* xa65 - 65xx/65816 cross-assembler and utility suite
2  *
3  * Copyright (C) 1989-1997 Andr� Fachat (a.fachat@physik.tu-chemnitz.de)
4  * maintained by Cameron Kaiser (ckaiser@floodgap.com)
5  *
6  * Main program
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22 
23 #include <time.h>
24 #include <ctype.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #ifndef _MSC_VER
29 #include <unistd.h>
30 #endif
31 
32 /* macros */
33 #include "xad.h"
34 
35 /* structs and defs */
36 #include "xah.h"
37 #include "xah2.h"
38 
39 /* exported functions are defined here */
40 #include "xa.h"
41 #include "xal.h"
42 #include "xam.h"
43 #include "xao.h"
44 #include "xap.h"
45 #include "xar.h"
46 #include "xat.h"
47 #include "xacharset.h"
48 
49 #include "version.h"
50 
51 /* ANZERR: total number of errors */
52 /* ANZWARN: total number of warnings */
53 
54 #define ANZERR		64
55 #define ANZWARN		13
56 
57 #define programname	"xa"
58 #define progversion	"v2.3.12"
59 #define authors		"Written by Andre Fachat, Jolse Maginnis, David Weinehall and Cameron Kaiser"
60 #define copyright	"Copyright (C) 1989-2021 Andre Fachat, Jolse Maginnis, David Weinehall\nand Cameron Kaiser."
61 
62 /* exported globals */
63 int ncmos, cmosfl, w65816, n65816;
64 int masm = 0;
65 int ppinstr = 0;
66 int nolink = 0;
67 int romable = 0;
68 int romaddr = 0;
69 int noglob = 0;
70 int showblk = 0;
71 int crossref = 0;
72 char altppchar;
73 
74 /* local variables */
75 static char out[MAXLINE];
76 static time_t tim1, tim2;
77 static FILE *fpout, *fperr, *fplab;
78 static int ner = 0;
79 
80 static int align = 1;
81 
82 static void printstat(void);
83 static void usage(int, FILE *);
84 static int setfext(char *, char *);
85 static int x_init(void);
86 static int pass1(void);
87 static int pass2(void);
88 static int puttmp(int);
89 static int puttmps(signed char *, int);
90 static void chrput(int);
91 static int xa_getline(char *);
92 static void lineout(void);
93 static long ga_p1(void);
94 static long gm_p1(void);
95 
96 /* text */
97 int memode,xmode;
98 int segment;
99 int tlen=0, tbase=0x1000;
100 int dlen=0, dbase=0x0400;
101 int blen=0, bbase=0x4000;
102 int zlen=0, zbase=4;
103 int fmode=0;
104 int relmode=0;
105 
106 int pc[SEG_MAX];	/* segments */
107 
main(int argc,char * argv[])108 int main(int argc,char *argv[])
109 {
110      int er=1,i;
111      signed char *s=NULL;
112      char *tmpp;
113 
114      int mifiles = 5;
115      int nifiles = 0;
116      int verbose = 0;
117      int oldfile = 0;
118      int no_link = 0;
119 
120      char **ifiles;
121      char *ofile;
122      char *efile;
123      char *lfile;
124      char *ifile;
125 
126      char old_e[MAXLINE];
127      char old_l[MAXLINE];
128      char old_o[MAXLINE];
129 
130      tim1=time(NULL);
131 
132      ncmos=0;
133      n65816=0;
134      cmosfl=1;
135      w65816=0;	/* default: 6502 only */
136 
137      altppchar = '#' ; /* i.e., NO alternate char */
138 
139      if((tmpp = strrchr(argv[0],'/'))) {
140 	tmpp++;
141      } else {
142 	tmpp = argv[0];
143      }
144      if( (!strcmp(tmpp,"xa65816"))
145 	|| (!strcmp(tmpp,"XA65816"))
146 	|| (!strcmp(tmpp,"xa816"))
147 	|| (!strcmp(tmpp,"XA816"))
148 	) {
149 	w65816 = 1;	/* allow 65816 per default */
150      }
151 
152      /* default output charset for strings in quotes */
153      set_charset("ASCII");
154 
155      ifiles = malloc(mifiles*sizeof(char*));
156 
157      afile = alloc_file();
158 
159      if (argc <= 1) {
160           usage(w65816, stderr);
161           exit(1);
162      }
163 
164      if (strstr(argv[1], "--help")) {
165           usage(w65816, stdout);
166 	  exit(0);
167      }
168 
169      if (strstr(argv[1], "--version")) {
170           version(programname, progversion, authors, copyright);
171 	  exit(0);
172      }
173 
174      ofile="a.o65";
175      efile=NULL;
176      lfile=NULL;
177 
178      if(pp_init()) {
179        logout("fatal: pp: no memory!");
180        return 1;
181      }
182      if(b_init()) {
183        logout("fatal: b: no memory!");
184        return 1;
185      }
186      if(l_init()) {
187        logout("fatal: l: no memory!");
188        return 1;
189      }
190 
191      i=1;
192      while(i<argc) {
193 	if(argv[i][0]=='-') {
194 	  switch(argv[i][1]) {
195 	  case 'p':
196 		/* intentionally not allowing an argument to follow with a
197 			space to avoid - being seen as the alternate
198 			preprocessor char! */
199 		if (argv[i][2] == '\0') {
200 			fprintf(stderr, "-p requires a character argument\n");
201 			exit(1);
202 		}
203 		if (argv[i][2] == '#')
204 			fprintf(stderr,
205 				"using -p# is evidence of stupidity\n");
206 		altppchar = argv[i][2];
207 		if (argv[i][3] != '\0')
208 			fprintf(stderr,
209 				"warning: extra characters to -p ignored\n");
210 		break;
211 	  case 'M':
212 		masm = 1;	/* MASM compatibility mode */
213 		break;
214           case 'S':
215                 ppinstr = 1;    /* preprocessor substitution in strings ok */
216                 fprintf(stderr, "Warning: -S is deprecated and will be removed in 2.4+!\n");
217 		break;
218 	  case 'O':		/* output charset */
219 		{
220 		  char *name = NULL;
221 		  if (argv[i][2] == 0) {
222 		    name = argv[++i];
223 		  } else {
224 		    name = argv[i]+2;
225 		  }
226 		  if (set_charset(name) < 0) {
227 		    fprintf(stderr, "Output charset name '%s' unknown - ignoring! (check case?)\n", name);
228 		  }
229 		}
230 		break;
231 	  case 'A':		/* make text segment start so that text relocation
232 				   is not necessary when _file_ starts at adr */
233 		romable = 2;
234 		if(argv[i][2]==0) romaddr = atoi(argv[++i]);
235 		else romaddr = atoi(argv[i]+2);
236 		break;
237 	  case 'G':
238 		noglob = 1;
239 		break;
240 	  case 'L':		/* define global label */
241 		if(argv[i][2]) lg_set(argv[i]+2);
242 		break;
243 	  case 'r':
244 		crossref = 1;
245 		break;
246 	  case 'R':
247 		relmode = 1;
248 		break;
249 	  case 'D':
250 		s = (signed char*)strstr(argv[i]+2,"=");
251 		if(s) *s = ' ';
252 		pp_define(argv[i]+2);
253 		break;
254 	  case 'c':
255 		no_link = 1;
256 		fmode |= FM_OBJ;
257 		break;
258 	  case 'v':
259 		verbose = 1;
260 		break;
261 	  case 'C':
262 		cmosfl = 0;
263 		break;
264           case 'W':
265                 w65816 = 0;
266                 break;
267           case 'w':
268                 w65816 = 1;
269                 break;
270 	  case 'B':
271 		showblk = 1;
272 		break;
273 	  case 'x':		/* old filename behaviour */
274 		oldfile = 1;
275 		fprintf(stderr, "Warning: -x is now deprecated and will be removed in 2.4+!\n");
276 		break;
277 	  case 'I':
278 		if(argv[i][2]==0) {
279 		  reg_include(argv[++i]);
280 		} else {
281 		  reg_include(argv[i]+2);
282 		}
283 		break;
284 	  case 'o':
285 		if(argv[i][2]==0) {
286 		  ofile=argv[++i];
287 		} else {
288 		  ofile=argv[i]+2;
289 		}
290 		break;
291 	  case 'l':
292 		if(argv[i][2]==0) {
293 		  lfile=argv[++i];
294 		} else {
295 		  lfile=argv[i]+2;
296 		}
297 		break;
298 	  case 'e':
299 		if(argv[i][2]==0) {
300 		  efile=argv[++i];
301 		} else {
302 		  efile=argv[i]+2;
303 		}
304 		break;
305 	  case 'b':			/* set segment base addresses */
306 		switch(argv[i][2]) {
307 		case 't':
308 			if(argv[i][3]==0) tbase = atoi(argv[++i]);
309 			else tbase = atoi(argv[i]+3);
310 			break;
311 		case 'd':
312 			if(argv[i][3]==0) dbase = atoi(argv[++i]);
313 			else dbase = atoi(argv[i]+3);
314 			break;
315 		case 'b':
316 			if(argv[i][3]==0) bbase = atoi(argv[++i]);
317 			else bbase = atoi(argv[i]+3);
318 			break;
319 		case 'z':
320 			if(argv[i][3]==0) zbase = atoi(argv[++i]);
321 			else zbase = atoi(argv[i]+3);
322 			break;
323 		default:
324 			fprintf(stderr,"unknown segment type '%c' - ignoring!\n",
325 								argv[i][2]);
326 			break;
327 		}
328 		break;
329 	  case 0:
330 		fprintf(stderr, "Single dash '-' on command line - ignoring!\n");
331 		break;
332 	  default:
333 		fprintf(stderr, "Unknown option '%c' - ignoring!\n",argv[i][1]);
334 		break;
335 	  }
336 	} else {		/* no option -> filename */
337 	  ifiles[nifiles++] = argv[i];
338 	  if(nifiles>=mifiles) {
339 	    mifiles += 5;
340 	    ifiles=realloc(ifiles, mifiles*sizeof(char*));
341 	    if(!ifiles) {
342 		fprintf(stderr, "Oops: couldn't alloc enough mem for filelist table..!\n");
343 		exit(1);
344 	    }
345 	  }
346 	}
347 	i++;
348      }
349      if(!nifiles) {
350 	fprintf(stderr, "No input files given!\n");
351 	exit(0);
352      }
353 
354      if(oldfile) {
355 	strcpy(old_e, ifiles[0]);
356 	strcpy(old_o, ifiles[0]);
357 	strcpy(old_l, ifiles[0]);
358 
359 	if(setfext(old_e,".err")==0) efile = old_e;
360 	if(setfext(old_o,".obj")==0) ofile = old_o;
361 	if(setfext(old_l,".lab")==0) lfile = old_l;
362      }
363      if(verbose) fprintf(stderr, "%s\n",copyright);
364 
365      fplab= lfile ? xfopen(lfile,"w") : NULL;
366      fperr= efile ? xfopen(efile,"w") : NULL;
367      if(!strcmp(ofile,"-")) {
368 	ofile=NULL;
369         fpout = stdout;
370      } else {
371         fpout= xfopen(ofile,"wb");
372      }
373      if(!fpout) {
374 	fprintf(stderr, "Couldn't open output file!\n");
375 	exit(1);
376      }
377 
378      if(1 /*!m_init()*/)
379      {
380        if(1 /*!b_init()*/)
381        {
382          if(1 /*!l_init()*/)
383          {
384            /*if(!pp_init())*/
385            {
386              if(!x_init())
387              {
388 	       /* if(fperr) fprintf(fperr,"%s\n",copyright); */
389 	       if(verbose) logout(ctime(&tim1));
390 
391 	       /* Pass 1 */
392 
393                pc[SEG_ABS]= 0;		/* abs addressing */
394 	       seg_start(fmode, tbase, dbase, bbase, zbase, 0, relmode);
395 
396 	       if(relmode) {
397 		 r_mode(RMODE_RELOC);
398 		 segment = SEG_TEXT;
399 	       } else {
400 		 /* prime old_segment in r_mode with SEG_TEXT */
401 	         segment = SEG_ABS;
402 		 r_mode(RMODE_ABS);
403 	       }
404 
405 	       nolink = no_link;
406 
407                for (i=0; i<nifiles; i++)
408                {
409 		 ifile = ifiles[i];
410 
411                  sprintf(out,"xAss65: Pass 1: %s\n",ifile);
412                  if(verbose) logout(out);
413 
414                  er=pp_open(ifile);
415                     puttmp(0);
416                     puttmp(T_FILE);
417                     puttmp(0);
418                     puttmp(0);
419                     puttmps((signed char*)&ifile, sizeof(filep->fname));
420 
421                  if(!er) {
422                    er=pass1();
423                    pp_close();
424                  } else {
425 		   sprintf(out, "Couldn't open source file '%s'!\n", ifile);
426 		   logout(out);
427                  }
428                }
429 
430 	       if((er=b_depth())) {
431 		 sprintf(out,"Still %d blocks open at end of file!\n",er);
432 		 logout(out);
433 	       }
434 
435 	       if(tbase & (align-1)) {
436 		   sprintf(out,"Warning: text segment ($%04x) start address doesn't align to %d!\n", tbase, align);
437 		   logout(out);
438 	       }
439 	       if(dbase & (align-1)) {
440 		   sprintf(out,"Warning: data segment ($%04x) start address doesn't align to %d!\n", dbase, align);
441 		   logout(out);
442 	       }
443 	       if(bbase & (align-1)) {
444 		   sprintf(out,"Warning: bss segment ($%04x) start address doesn't align to %d!\n", bbase, align);
445 		   logout(out);
446 	       }
447 	       if(zbase & (align-1)) {
448 		   sprintf(out,"Warning: zero segment ($%04x) start address doesn't align to %d!\n", zbase, align);
449 		   logout(out);
450 	       }
451                if (n65816>0)
452                    fmode |= 0x8000;
453 	       switch(align) {
454 		case 1: break;
455 		case 2: fmode |= 1; break;
456 		case 4: fmode |= 2; break;
457 		case 256: fmode |=3; break;
458 	       }
459 
460 	       if((!er) && relmode)
461 			h_write(fpout, fmode, tlen, dlen, blen, zlen, 0);
462 
463 
464                if(!er)
465                {
466                     if(verbose) logout("xAss65: Pass 2:\n");
467 
468 		    seg_pass2();
469 
470 	     	    if(relmode) {
471 		 	r_mode(RMODE_RELOC);
472 		 	segment = SEG_TEXT;
473 	            } else {
474 		 	/* prime old_segment in r_mode with SEG_TEXT */
475 	         	segment = SEG_ABS;
476 		 	r_mode(RMODE_ABS);
477 	            }
478                     er=pass2();
479                }
480 
481                if(fplab) printllist(fplab);
482                tim2=time(NULL);
483 	       if(verbose) printstat();
484 
485 	       if((!er) && relmode) seg_end(fpout);	/* write reloc/label info */
486 
487                if(fperr) fclose(fperr);
488                if(fplab) fclose(fplab);
489                if(fpout) fclose(fpout);
490 
491              } else {
492                logout("fatal: x: no memory!\n");
493              }
494              pp_end();
495 /*           } else {
496              logout("fatal: pp: no memory!");*/
497            }
498          } else {
499           logout("fatal: l: no memory!\n");
500          }
501        } else {
502           logout("fatal: b: no memory!\n");
503        }
504        /*m_exit();*/
505      } else {
506           logout("Not enough memory available!\n");
507      }
508 
509      if(ner || er)
510      {
511           fprintf(stderr, "Break after %d error%c\n",ner,ner?'s':0);
512 	  /*unlink();*/
513 	  if(ofile) {
514 	    unlink(ofile);
515 	  }
516      }
517 
518      free(ifiles);
519 
520      return( (er || ner) ? 1 : 0 );
521 }
522 
printstat(void)523 static void printstat(void)
524 {
525 	logout("Statistics:\n");
526 	sprintf(out," %8d of %8d label used\n",ga_lab(),gm_lab()); logout(out);
527 	sprintf(out," %8ld of %8ld byte label-memory used\n",ga_labm(),gm_labm()); logout(out);
528 	sprintf(out," %8d of %8d PP-defs used\n",ga_pp(),gm_pp()); logout(out);
529 	sprintf(out," %8ld of %8ld byte PP-memory used\n",ga_ppm(),gm_ppm()); logout(out);
530 	sprintf(out," %8ld of %8ld byte buffer memory used\n",ga_p1(),gm_p1()); logout(out);
531 	sprintf(out," %8d blocks used\n",ga_blk()); logout(out);
532 	sprintf(out," %8ld seconds used\n",(long)difftime(tim2,tim1)); logout(out);
533 }
534 
h_length(void)535 int h_length(void) {
536 	return 26+o_length();
537 }
538 
539 #if 0
540 /* write header for relocatable output format */
541 int h_write(FILE *fp, int tbase, int tlen, int dbase, int dlen,
542 				int bbase, int blen, int zbase, int zlen) {
543 
544 	fputc(1, fp);			/* version byte */
545 	fputc(0, fp);			/* hi address 0 -> no C64 */
546 	fputc("o", fp);
547 	fputc("6", fp);
548 	fputc("5", fp);
549 	fputc(0, fp);			/* format version */
550 	fputw(mode, fp);		/* file mode */
551 	fputw(tbase,fp);		/* text base */
552 	fputw(tlen,fp);			/* text length */
553 	fputw(dbase,fp);		/* data base */
554 	fputw(dlen,fp);			/* data length */
555 	fputw(bbase,fp);		/* bss base */
556 	fputw(blen,fp);			/* bss length */
557 	fputw(zbase,fp);		/* zerop base */
558 	fputw(zlen,fp);			/* zerop length */
559 
560 	o_write(fp);
561 
562 	return 0;
563 }
564 #endif
565 
setfext(char * s,char * ext)566 static int setfext(char *s, char *ext)
567 {
568      int j,i=(int)strlen(s);
569 
570      if(i>MAXLINE-5)
571           return(-1);
572 
573      for(j=i-1;j>=0;j--)
574      {
575           if(s[j]==DIRCHAR)
576           {
577                strcpy(s+i,ext);
578                break;
579           }
580           if(s[j]=='.')
581           {
582                strcpy(s+j,ext);
583                break;
584           }
585      }
586      if(!j)
587           strcpy(s+i,ext);
588 
589      return(0);
590 }
591 
592 /*
593 static char *tmp;
594 static unsigned long tmpz;
595 static unsigned long tmpe;
596 */
597 
ga_p1(void)598 static long ga_p1(void)
599 {
600 	return(afile->mn.tmpz);
601 }
gm_p1(void)602 static long gm_p1(void)
603 {
604 	return(TMPMEM);
605 }
606 
pass2(void)607 static int pass2(void)
608 {
609      int c,er,l,ll,i,al;
610      Datei datei;
611      signed char *dataseg=NULL;
612      signed char *datap=NULL;
613 
614      memode=0;
615      xmode=0;
616      if((dataseg=malloc(dlen))) {
617        if(!dataseg) {
618 	 fprintf(stderr, "Couldn't alloc dataseg memory...\n");
619 	 exit(1);
620        }
621        datap=dataseg;
622      }
623      filep=&datei;
624      afile->mn.tmpe=0L;
625 
626      while(ner<20 && afile->mn.tmpe<afile->mn.tmpz)
627      {
628           l=afile->mn.tmp[afile->mn.tmpe++];
629           ll=l;
630 
631           if(!l)
632           {
633                if(afile->mn.tmp[afile->mn.tmpe]==T_LINE)
634                {
635                     datei.fline=(afile->mn.tmp[afile->mn.tmpe+1]&255)+(afile->mn.tmp[afile->mn.tmpe+2]<<8);
636                     afile->mn.tmpe+=3;
637                } else
638                if(afile->mn.tmp[afile->mn.tmpe]==T_FILE)
639                {
640                     datei.fline=(afile->mn.tmp[afile->mn.tmpe+1]&255)+(afile->mn.tmp[afile->mn.tmpe+2]<<8);
641 
642 		    memcpy(&datei.fname, afile->mn.tmp+afile->mn.tmpe+3, sizeof(datei.fname));
643                     afile->mn.tmpe+=3+sizeof(datei.fname);
644 /*
645 		    datei.fname = malloc(strlen((char*) afile->mn.tmp+afile->mn.tmpe+3)+1);
646 		    if(!datei.fname) {
647 			fprintf(stderr,"Oops, no more memory\n");
648 			exit(1);
649 		    }
650                     strcpy(datei.fname,(char*) afile->mn.tmp+afile->mn.tmpe+3);
651                     afile->mn.tmpe+=3+strlen(datei.fname);
652 */
653                }
654           } else
655           {
656 /* do not attempt address mode optimization on pass 2 */
657                er=t_p2(afile->mn.tmp+afile->mn.tmpe,&ll,1,&al);
658 
659                if(er==E_NOLINE)
660                {
661                } else
662                if(er==E_OK)
663                {
664 		  if(segment<SEG_DATA) {
665                     for(i=0;i<ll;i++)
666                          chrput(afile->mn.tmp[afile->mn.tmpe+i]);
667 		  } else if (segment==SEG_DATA && datap) {
668 		    memcpy(datap,afile->mn.tmp+afile->mn.tmpe,ll);
669 		    datap+=ll;
670 		  }
671                } else
672                if(er==E_DSB)
673                {
674                   c=afile->mn.tmp[afile->mn.tmpe];
675 		  if(segment<SEG_DATA) {
676                     /*printf("E_DSB, ll=%d, l=%d, c=%c\n",ll,l,afile->mn.tmp[afile->mn.tmpe]);*/
677                     for(i=0;i<ll;i++)
678                          chrput(c);
679 		  } else if (segment==SEG_DATA && datap) {
680 		    memset(datap, c, ll);
681 		    datap+=ll;
682 		  }
683                } else if (er == E_BIN) {
684 			int i;
685 			int j;
686 			int flen;
687 			int offset;
688 			int fstart;
689 			FILE *foo;
690 			char binfnam[256];
691 
692 			i = afile->mn.tmpe;
693 /*
694 			fprintf(stderr, "ok, ready to insert\n");
695 			for (i=0; i<ll; i++) {
696 fprintf(stderr, "%i: %02x\n", i, afile->mn.tmp[afile->mn.tmpe+i]);
697 			}
698 */
699 
700 			offset = afile->mn.tmp[i] +
701 				(afile->mn.tmp[i+1] << 8) +
702 				(afile->mn.tmp[i+2] << 16);
703 			fstart = afile->mn.tmp[i+3] + 1 +
704 				(afile->mn.tmp[i+4] << 8);
705 			/* usually redundant but here for single-char names
706 				that get interpreted as chars */
707 			flen = afile->mn.tmp[i+5];
708 			if (flen > 1) fstart++;
709 			/* now fstart points either to string past quote and
710 				length mark, OR, single char byte */
711 /*
712 fprintf(stderr, "offset = %i length = %i fstart = %i flen = %i charo = %c\n",
713 		offset, ll, fstart, flen, afile->mn.tmp[afile->mn.tmpe+fstart]);
714 */
715 			/* there is a race condition here where altering the
716 				file between validation in t_p2 (xat.c) and
717 				here will cause problems. I'm not going to
718 				worry about this right now. */
719 
720 			for(j=0; j<flen; j++) {
721 				binfnam[j] = afile->mn.tmp[i+fstart+j];
722 			}
723 			binfnam[flen] = '\0';
724 /*
725 			fprintf(stderr, "fnam = %s\n", binfnam);
726 */
727 			/* primitive insurance */
728 			if (!(foo = fopen(binfnam, "rb"))) {
729 				errout(E_FNF);
730 				ner++;
731 			} else {
732 				fseek(foo, offset, SEEK_SET);
733 				for(j=0; j<ll; j++) {
734 					/* damn you Andre ;-) */
735 					i = fgetc(foo);
736 					if (segment<SEG_DATA) {
737 						chrput(i);
738 					}
739 					if (segment==SEG_DATA && datap) {
740 						memset(datap++, i, 1);
741 					}
742 				}
743 				fclose(foo);
744 			}
745 		} else {
746                     errout(er);
747                }
748           }
749           afile->mn.tmpe+=abs(l);
750      }
751      if(relmode) {
752        if((ll=fwrite(dataseg, 1, dlen, fpout))<dlen) {
753 	fprintf(stderr, "Problems writing %d bytes, return gives %d\n",dlen,ll);
754        }
755      }
756 
757      return(ner);
758 }
759 
760 
pass1(void)761 static int pass1(void)
762 {
763      signed char o[MAXLINE];
764      int l,er,temp_er,al;
765 
766      memode=0;
767      xmode=0;
768      tlen=0;
769      ner=0;
770 
771 	temp_er = 0;
772 
773 /*FIXIT*/
774      while(!(er=xa_getline(s)))
775      {
776           er=t_p1((signed char*)s,o,&l,&al);
777 	  switch(segment) {
778 	    case SEG_ABS:
779 	    case SEG_TEXT: tlen += al; break;
780 	    case SEG_DATA: dlen += al; break;
781 	    case SEG_BSS : blen += al; break;
782 	    case SEG_ZERO: zlen += al; break;
783 	  }
784 
785           /*printf(": er= %d, l=%d, tmpz=%d\n",er,l,tmpz); */
786 
787           if(l)
788           {
789             if(er)
790             {
791                if(er==E_OKDEF)
792                {
793                     if(!(er=puttmp(l)))
794                          er=puttmps(o,l);
795                } else
796                if(er==E_NOLINE)
797                     er=E_OK;
798             } else
799             {
800                if(!(er=puttmp(-l)))
801                     er=puttmps(o,l);
802             }
803           }
804           if(er)
805           {
806                lineout();
807                errout(er);
808           }
809 
810 /*          printf("tmpz =%d\n",afile->mn.tmpz);
811 */
812      }
813 
814      if(er!=E_EOF) {
815           errout(er);
816 	}
817 
818 
819 
820 /*     { int i; printf("Pass 1 \n");
821      for(i=0;i<afile->mn.tmpz;i++)
822           fprintf(stderr, " %02x",255 & afile->mn.tmp[i]);
823      getchar();}
824 */
825      return(ner);
826 }
827 
usage(int default816,FILE * fp)828 static void usage(int default816, FILE *fp)
829 {
830      fprintf(fp,
831 	    "Usage: %s [options] file\n"
832 	    "Cross-assembler for 65xx/R65C02/65816\n"
833 	    "\n",
834             programname);
835 	fprintf(fp,
836 	    " -v           verbose output\n"
837             " -C           no CMOS-opcodes\n"
838             " -W           no 65816-opcodes%s\n"
839             " -w           allow 65816-opcodes%s\n",
840 	    default816 ? "" : " (default)",
841 	    default816 ? " (default)" : "");
842 	fprintf(fp,
843             " -B           show lines with block open/close\n"
844             " -c           produce `o65' object instead of executable files (i.e. don't link)\n"
845 	    " -o filename  sets output filename, default is `a.o65'\n"
846 	    "                A filename of `-' sets stdout as output file\n");
847 	fprintf(fp,
848 	    " -e filename  sets errorlog filename, default is none\n"
849 	    " -l filename  sets labellist filename, default is none\n"
850 	    " -r           adds crossreference list to labellist (if `-l' given)\n"
851 	    " -M           allow ``:'' to appear in comments for MASM compatibility\n"
852 	    " -R           start assembler in relocating mode\n");
853 	fprintf(fp,
854 	    " -Llabel      defines `label' as absolute, undefined label even when linking\n"
855 	    " -b? addr     set segment base address to integer value addr\n"
856 	    "                `?' stands for t(ext), d(ata), b(ss) and z(ero) segment\n"
857 	    "                (address can be given more than once, last one is used)\n");
858 	fprintf(fp,
859 	    " -A addr      make text segment start at an address that when the _file_\n"
860 	    "                starts at addr, relocation is not necessary. Overrides -bt\n"
861 	    "                Other segments must be specified with `-b?'\n"
862 	    " -G           suppress list of exported globals\n");
863 	fprintf(fp,
864 	    " -p?          set preprocessor character to ?, default is #\n"
865 	    " -DDEF=TEXT   defines a preprocessor replacement\n"
866 	    " -Ocharset    set output charset (PETSCII, ASCII, etc.), case-sensitive\n"
867 	    " -Idir        add directory `dir' to include path (before XAINPUT)\n"
868 	    "  --version   output version information and exit\n"
869 	    "  --help      display this help and exit\n");
870 	fprintf(fp,
871 	    "== These options are deprecated and will be removed in 2.4+! ==\n"
872 	    " -x           old filename behaviour (overrides `-o', `-e', `-l')\n"
873 	    " -S           allow preprocessor substitution within strings\n");
874 }
875 
876 /*
877 static char *ertxt[] = { "Syntax","Label definiert",
878           "Label nicht definiert","Labeltabelle voll",
879           "Label erwartet","Speicher voll","Illegaler Opcode",
880           "Falsche Adressierungsart","Branch ausserhalb des Bereichs",
881           "Ueberlauf","Division durch Null","Pseudo-Opcode erwartet",
882           "Block-Stack-Ueberlauf","Datei nicht gefunden",
883           "End of File","Block-Struktur nicht abgeschlossen",
884           "NoBlk","NoKey","NoLine","OKDef","DSB","NewLine",
885           "NewFile","CMOS-Befehl","pp:Falsche Anzahl Parameter" };
886 */
887 static char *ertxt[] = {
888 	"Syntax",
889 	"Label already defined",
890         "Label not defined",
891 	"Label table full",
892         "Label expected",
893 	"Out of memory",
894 	"Illegal opcode",
895         "Wrong addressing mode",
896 	"Branch out of range",
897         "Overflow",
898 	"Division by zero",
899 	"Pseudo-opcode expected",
900         "Block stack overflow",
901 	"File not found",
902         "End of file",
903 	"Unmatched block close",
904         "NoBlk",
905 	"NoKey",
906 	"NoLine",
907 	"OKDef",
908 	"DSB",
909 	"NewLine",
910         "NewFile",
911 	"CMOS instruction used with -C",
912 	"pp:Wrong parameter count",
913 	"Illegal pointer arithmetic",
914 	"Illegal segment",
915 	"File header option too long",
916 	"File option not at file start (when ROM-able)",
917 	"Illegal align value",
918         "65816 mode used/required",
919 	"Exceeded recursion limit for label evaluation",
920 	"Unresolved preprocessor directive at end of file",
921 	"Data underflow",
922 	"Illegal quantity",
923 	".bin",
924 /* placeholders for future fatal errors */
925 		"",
926 		"",
927 		"",
928 		"",
929 		"",
930 		"",
931 		"",
932 		"",
933 		"",
934 		"",
935 		"",
936 		"",
937 		"",
938 		"",
939 		"",
940 		"",
941 		"",
942 		"",
943 		"",
944 		"",
945 		"",
946 		"",
947 		"",
948 		"",
949 		"",
950 		"",
951 		"",
952 		"",
953 /* warnings */
954 	  "Cutting word relocation in byte value",
955 	  "Byte relocation in word value",
956 	  "Illegal pointer arithmetic",
957 	  "Address access to low or high byte pointer",
958 	  "High byte access to low byte pointer",
959 	  "Low byte access to high byte pointer",
960 	  "Can't optimize forward-defined label; using absolute addressing",
961 	  "Open preprocessor directive at end of file (intentional?)",
962 	  "Included binary data exceeds 64KB",
963 	  "Included binary data exceeds 16MB",
964           "MVN/MVP $XXXX syntax is deprecated and will be removed",
965 /* more placeholders */
966 		"",
967 		"",
968 
969  };
970 
971 static int gl;
972 static int gf;
973 
x_init(void)974 static int x_init(void)
975 {
976 	return 0;
977 #if 0
978      int er=0;
979      /*er=m_alloc(TMPMEM,&tmp);*/
980      afile->mn.tmp=malloc(TMPMEM);
981      if(!afile->mn.tmp) er=E_NOMEM;
982      afile->mn.tmpz=0L;
983      return(er);
984 #endif
985 }
986 
puttmp(int c)987 static int puttmp(int c)
988 {
989      int er=E_NOMEM;
990 /*printf("puttmp: afile=%p, tmp=%p, tmpz=%d\n",afile, afile?afile->mn.tmp:0, afile?afile->mn.tmpz:0);*/
991      if(afile->mn.tmpz<TMPMEM)
992      {
993           afile->mn.tmp[afile->mn.tmpz++]=c;
994           er=E_OK;
995      }
996      return(er);
997 }
998 
puttmps(signed char * s,int l)999 static int puttmps(signed char *s, int l)
1000 {
1001      int i=0,er=E_NOMEM;
1002 
1003      if(afile->mn.tmpz+l<TMPMEM)
1004      {
1005           while(i<l)
1006                afile->mn.tmp[afile->mn.tmpz++]=s[i++];
1007 
1008           er=E_OK;
1009      }
1010      return(er);
1011 }
1012 
1013 static char l[MAXLINE];
1014 
xa_getline(char * s)1015 static int xa_getline(char *s)
1016 {
1017      static int ec;
1018 
1019      static int i,c;
1020      int hkfl,j,comcom;
1021 
1022      j=hkfl=comcom=0;
1023      ec=E_OK;
1024 
1025      if(!gl)
1026      {
1027           do
1028           {
1029                ec=pgetline(l);
1030                i=0;
1031                while(l[i]==' ')
1032                     i++;
1033                while(l[i]!='\0' && isdigit(l[i]))
1034                     i++;
1035                gf=1;
1036 
1037                if(ec==E_NEWLINE)
1038                {
1039                     puttmp(0);
1040                     puttmp(T_LINE);
1041                     puttmp((filep->fline)&255);
1042                     puttmp(((filep->fline)>>8)&255);
1043 		ec=E_OK;
1044 
1045                }
1046 		else
1047                if(ec==E_NEWFILE)
1048                {
1049                     puttmp(0);
1050                     puttmp(T_FILE);
1051                     puttmp((filep->fline)&255);
1052                     puttmp(((filep->fline)>>8)&255);
1053 		    puttmps((signed char*)&(filep->fname), sizeof(filep->fname));
1054 /*
1055                     puttmps((signed char*)filep->fname,
1056 					1+(int)strlen(filep->fname));
1057 */
1058                     ec=E_OK;
1059                }
1060           } while(!ec && l[i]=='\0');
1061      }
1062 
1063      gl=0;
1064      if(!ec || ec==E_EOF)
1065      {
1066           do {
1067                c=s[j]=l[i++];
1068 
1069                 if (!(hkfl&2) && c=='\"')
1070                     hkfl^=1;
1071                 if (!comcom && !(hkfl&1) && c=='\'')
1072                     hkfl^=2;
1073 		if (c==';' && !hkfl)
1074 			comcom = 1;
1075                if (c=='\0')
1076                     break;	/* hkfl = comcom = 0 */
1077 		if (c==':' && !hkfl && (!comcom || !masm)) {
1078                     		gl=1;
1079                     		break;
1080                }
1081                j++;
1082           } while (c!='\0' && j<MAXLINE-1 && i<MAXLINE-1);
1083 
1084           s[j]='\0';
1085      } else
1086           s[0]='\0';
1087 
1088      return(ec);
1089 }
1090 
set_align(int a)1091 void set_align(int a) {
1092 	align = (a>align)?a:align;
1093 }
1094 
lineout(void)1095 static void lineout(void)
1096 {
1097      if(gf)
1098      {
1099           logout(filep->flinep);
1100           logout("\n");
1101           gf=0;
1102      }
1103 }
1104 
errout(int er)1105 void errout(int er)
1106 {
1107      if (er<-ANZERR || er>-1) {
1108 	if(er>=-(ANZERR+ANZWARN) && er < -ANZERR) {
1109 	  sprintf(out,"%s:line %d: %04x: Warning - %s\n",
1110 		filep->fname, filep->fline, pc[segment], ertxt[(-er)-1]);
1111 	} else {
1112           /* sprintf(out,"%s:Zeile %d: %04x:Unbekannter Fehler Nr.: %d\n",*/
1113           sprintf(out,"%s:line %d: %04x: Unknown error # %d\n",
1114                filep->fname,filep->fline,pc[segment],er);
1115 	  ner++;
1116 	}
1117      } else {
1118        if (er==E_NODEF)
1119           sprintf(out,"%s:line %d: %04x:Label '%s' not defined\n",
1120                filep->fname,filep->fline,pc[segment],lz);
1121        else
1122           sprintf(out,"%s:line %d: %04x:%s error\n",
1123                filep->fname,filep->fline,pc[segment],ertxt[(-er)-1]);
1124 
1125        ner++;
1126      }
1127      logout(out);
1128 }
1129 
chrput(int c)1130 static void chrput(int c)
1131 {
1132      /*     printf(" %02x",c&255);*/
1133 
1134      putc( c&0x00ff,fpout);
1135 }
1136 
logout(char * s)1137 void logout(char *s)
1138 {
1139      fprintf(stderr, "%s",s);
1140      if(fperr)
1141           fprintf(fperr,"%s",s);
1142 }
1143 
1144