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