1 #include <stdio.h>
2 #include <strings.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include "defs.h"
6 #include "externs.h"
7 #include "protos.h"
8 
9 /* pseudo instructions section flag */
10 char pseudo_flag[] = {
11 	0x0C, 0x0C, 0x0F, 0x0F, 0x0F, 0x0C, 0x0C, 0x0C, 0x0F, 0x0C,
12 	0x0C, 0x0C, 0x0C, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
13 	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0C,
14 	0x0F, 0x0F, 0x0F, 0x0C, 0x0C, 0x0C, 0x0C, 0x0F, 0x0F, 0x0F,
15 	0x0F, 0x0F, 0x0C, 0x0C, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x04
16 };
17 
18 
19 /* ----
20  * do_pseudo()
21  * ----
22  * pseudo instruction processor
23  */
24 
25 void
do_pseudo(int * ip)26 do_pseudo(int *ip)
27 {
28 	char str[80];
29 	int old_bank;
30 	int size;
31 
32 	/* check if the directive is allowed in the current section */
33 	if (!(pseudo_flag[opval] & (1 << section)))
34 		fatal_error("Directive not allowed in the current section!");
35 
36 	/* save current location */
37 	old_bank = bank;
38 
39 	/* execute directive */
40 	opproc(ip);
41 
42 	/* reset last label pointer */
43 	switch (opval) {
44 	case P_VRAM:
45 	case P_PAL:
46 		break;
47 
48 	case P_DB:
49 	case P_DW:
50 		if (lastlabl) {
51 			if(lastlabl->data_type != P_DB)
52 		 	   lastlabl = NULL;
53 		}
54 		break;
55 
56 	default:
57 		if (lastlabl) {
58 			if(lastlabl->data_type != opval)
59 		 	   lastlabl = NULL;
60 		}
61 		break;
62 	}
63 
64 	/* bank overflow warning */
65 	if (pass == LAST_PASS) {
66 		if (asm_opt[OPT_WARNING]) {
67 			switch (opval) {
68 			case P_INCBIN:
69 			case P_INCCHR:
70 			case P_INCSPR:
71 			case P_INCPAL:
72 			case P_INCBAT:
73 			case P_INCTILE:
74 			case P_INCMAP:
75 				if (bank != old_bank) {
76 					size = ((bank - old_bank - 1) * 8192) + loccnt;
77 					if (size) {
78 						sprintf(str, "Warning, bank overflow by %i bytes!\n", size);
79 						warning(str);
80 					}
81 				}
82 				break;
83 			}
84 		}
85 	}
86 }
87 
88 
89 /* ----
90  * do_list()
91  * ----
92  * .list pseudo
93  */
94 
95 void
do_list(int * ip)96 do_list(int *ip)
97 {
98 	/* check end of line */
99 	if (!check_eol(ip))
100 		return;
101 
102 	asm_opt[OPT_LIST] = 1;
103 	xlist = 1;
104 }
105 
106 
107 /* ----
108  * do_mlist()
109  * ----
110  * .mlist pseudo
111  */
112 
113 void
do_mlist(int * ip)114 do_mlist(int *ip)
115 {
116 	/* check end of line */
117 	if (!check_eol(ip))
118 		return;
119 
120 	asm_opt[OPT_MACRO] = 1;
121 }
122 
123 
124 /* ----
125  * do_nolist()
126  * ----
127  * .nolist pseudo
128  */
129 
130 void
do_nolist(int * ip)131 do_nolist(int *ip)
132 {
133 	/* check end of line */
134 	if (!check_eol(ip))
135 		return;
136 
137 	asm_opt[OPT_LIST] = 0;
138 }
139 
140 
141 /* ----
142  * do_nomlist()
143  * ----
144  * .nomlist pseudo
145  */
146 
147 void
do_nomlist(int * ip)148 do_nomlist(int *ip)
149 {
150 	/* check end of line */
151 	if (!check_eol(ip))
152 		return;
153 
154 	asm_opt[OPT_MACRO] = mlist_opt;
155 }
156 
157 
158 /* ----
159  * do_db()
160  * ----
161  * .db pseudo
162  */
163 
164 void
do_db(int * ip)165 do_db(int *ip)
166 {
167 	unsigned char c;
168 
169 	/* define label */
170 	labldef(loccnt, 1);
171 
172 	/* output infos */
173 	data_loccnt = loccnt;
174 	data_level  = 2;
175 
176 	/* skip spaces */
177 	while (isspace(prlnbuf[++(*ip)]));
178 
179 	/* get bytes */
180 	for (;;) {
181 		/* ASCII string */
182 		if (prlnbuf[*ip] == '\"') {
183 			for (;;) {
184 				c = prlnbuf[++(*ip)];
185 				if (c == '\"')
186 					break;
187 				if (c == '\0') {
188 					error("Unterminated ASCII string!");
189 					return;
190 				}
191 				if (c == '\\') {
192 					c = prlnbuf[++(*ip)];
193 					switch(c) {
194 					case 'r':
195 						c = '\r';
196 						break;
197 					case 'n':
198 						c = '\n';
199 						break;
200 					case 't':
201 						c = '\t';
202 						break;
203 					}
204 				}
205 				/* store char on last pass */
206 				if (pass == LAST_PASS)
207 					putbyte(loccnt, c);
208 
209 				/* update location counter */
210 				loccnt++;
211 			}
212 			(*ip)++;
213 		}
214 		/* bytes */
215 		else {
216 			/* get a byte */
217 			if (!evaluate(ip, 0))
218 				return;
219 
220 			/* update location counter */
221 			loccnt++;
222 
223 			/* store byte on last pass */
224 			if (pass == LAST_PASS) {
225 				/* check for overflow */
226 				if ((value > 0xFF) && (value < 0xFFFFFF80)) {
227 					error("Overflow error!");
228 					return;
229 				}
230 
231 				/* store byte */
232 				putbyte(loccnt - 1, value);
233 			}
234 		}
235 
236 		/* check if there's another byte */
237 		c = prlnbuf[(*ip)++];
238 
239 		if (c != ',')
240 			break;
241 	}
242 
243 	/* check error */
244 	if (c != ';' && c != '\0') {
245 		error("Syntax error!");
246 		return;
247 	}
248 
249 	/* size */
250 	if (lablptr) {
251 		lablptr->data_type = P_DB;
252 		lablptr->data_size = loccnt - data_loccnt;
253 	}
254 	else {
255 		if (lastlabl) {
256 			if (lastlabl->data_type == P_DB)
257 				lastlabl->data_size += loccnt - data_loccnt;
258 		}
259 	}
260 
261 	/* output line */
262 	if (pass == LAST_PASS)
263 		println();
264 }
265 
266 
267 /* ----
268  * do_dw()
269  * ----
270  * .dw pseudo
271  */
272 
273 void
do_dw(int * ip)274 do_dw(int *ip)
275 {
276 	char c;
277 
278 	/* define label */
279 	labldef(loccnt, 1);
280 
281 	/* output infos */
282 	data_loccnt = loccnt;
283 	data_size   = 2;
284 	data_level  = 2;
285 
286 	/* get data */
287 	for (;;) {
288 		/* get a word */
289 		if (!evaluate(ip, 0))
290 			return;
291 
292 		/* update location counter */
293 		loccnt += 2;
294 
295 		/* store word on last pass */
296 		if (pass == LAST_PASS) {
297 			/* check for overflow */
298 			if ((value > 0xFFFF) && (value < 0xFFFF8000)) {
299 				error("Overflow error!");
300 				return;
301 			}
302 
303 			/* store word */
304 			putword(loccnt-2, value);
305 		}
306 
307 		/* check if there's another word */
308 		c = prlnbuf[(*ip)++];
309 
310 		if (c != ',')
311 			break;
312 	}
313 
314 	/* check error */
315 	if (c != ';' && c != '\0') {
316 		error("Syntax error!");
317 		return;
318 	}
319 
320 	/* size */
321 	if (lablptr) {
322 		lablptr->data_type = P_DB;
323 		lablptr->data_size = loccnt - data_loccnt;
324 	}
325 	else {
326 		if (lastlabl) {
327 			if (lastlabl->data_type == P_DB)
328 				lastlabl->data_size += loccnt - data_loccnt;
329 		}
330 	}
331 
332 	/* output line */
333 	if (pass == LAST_PASS)
334 		println();
335 }
336 
337 
338 /* ----
339  * do_equ()
340  * ----
341  * .equ pseudo
342  */
343 
344 void
do_equ(int * ip)345 do_equ(int *ip)
346 {
347 	/* get value */
348 	if (!evaluate(ip, ';'))
349 		return;
350 
351 	/* assign value to the label */
352 	labldef(value, 0);
353 
354 	/* output line */
355 	if (pass == LAST_PASS) {
356 		loadlc(value, 1);
357 		println();
358 	}
359 }
360 
361 
362 /* ----
363  * do_page()
364  * ----
365  * .page pseudo
366  */
367 
368 void
do_page(int * ip)369 do_page(int *ip)
370 {
371 	/* not allowed in procs */
372 	if (proc_ptr) {
373 		fatal_error("PAGE can not be changed in procs!");
374 		return;
375 	}
376 
377 	/* define label */
378 	labldef(loccnt, 1);
379 
380 	/* get page index */
381 	if (!evaluate(ip, ';'))
382 		return;
383 	if (value > 7) {
384 		error("Invalid page index!");
385 		return;
386 	}
387 	page = value;
388 
389 	/* output line */
390 	if (pass == LAST_PASS) {
391 		loadlc(value << 13, 1);
392 		println();
393 	}
394 }
395 
396 
397 /* ----
398  * do_org()
399  * ----
400  * .org pseudo
401  */
402 
403 void
do_org(int * ip)404 do_org(int *ip)
405 {
406 	/* get the .org value */
407 	if (!evaluate(ip, ';'))
408 		return;
409 
410 	/* check for undefined symbol - they are not allowed in .org */
411 	if (undef != 0) {
412 		error("Undefined symbol in operand field!");
413 		return;
414 	}
415 
416 	/* section switch */
417 	switch (section) {
418 	case S_ZP:
419 		/* zero page section */
420 		if ((value & 0xFFFFFF00) && ((value & 0xFFFFFF00) != machine->ram_base)) {
421 			error("Invalid address!");
422 			return;
423 		}
424 		break;
425 
426 	case S_BSS:
427 		/* ram section */
428 		if ((value < machine->ram_base) || (value >= (machine->ram_base + machine->ram_limit))) {
429 			error("Invalid address!");
430 			return;
431 		}
432 		break;
433 
434 	case S_CODE:
435 	case S_DATA:
436 		/* not allowed in procs */
437 		if (proc_ptr) {
438 			fatal_error("ORG can not be changed in procs!");
439 			return;
440 		}
441 
442 		/* code and data section */
443 		if (value & 0xFFFF0000) {
444 			error("Invalid address!");
445 			return;
446 		}
447 		page = (value >> 13) & 0x07;
448 		break;
449 	}
450 
451 	/* set location counter */
452 	loccnt = (value & 0x1FFF);
453 
454 	/* set label value if there was one */
455 	labldef(loccnt, 1);
456 
457 	/* output line on last pass */
458 	if (pass == LAST_PASS) {
459 		loadlc(value, 1);
460 		println();
461 	}
462 }
463 
464 
465 /* ----
466  * do_bank()
467  * ----
468  * .bank pseudo
469  */
470 
471 void
do_bank(int * ip)472 do_bank(int *ip)
473 {
474 	char name[128];
475 
476 	/* not allowed in procs */
477 	if (proc_ptr) {
478 		fatal_error("Bank can not be changed in procs!");
479 		return;
480 	}
481 
482 	/* define label */
483 	labldef(loccnt, 1);
484 
485 	/* get bank index */
486 	if (!evaluate(ip, 0))
487 		return;
488 	if (value > bank_limit) {
489 		error("Bank index out of range!");
490 		return;
491 	}
492 
493 	/* check if there's a bank name */
494 	switch (prlnbuf[*ip]) {
495 	case ';':
496 	case '\0':
497 		break;
498 
499 	case ',':
500 		/* get name */
501 		(*ip)++;
502 		if (!getstring(ip, name, 63))
503 			return;
504 
505 		/* check name validity */
506 		if (strlen(bank_name[value])) {
507 			if (strcasecmp(bank_name[value], name)) {
508 				error("Different bank names not allowed!");
509 				return;
510 			}
511 		}
512 
513 		/* copy name */
514 		strcpy(bank_name[value], name);
515 
516 		/* check end of line */
517 		if (!check_eol(ip))
518 			return;
519 
520 		/* ok */
521 		break;
522 
523 	default:
524 		error("Syntax error!");
525 		return;
526 	}
527 
528 	/* backup current bank infos */
529 	bank_glabl[section][bank]  = glablptr;
530 	bank_loccnt[section][bank] = loccnt;
531 	bank_page[section][bank]   = page;
532 
533 	/* get new bank infos */
534 	bank     = value;
535 	page     = bank_page[section][bank];
536 	loccnt   = bank_loccnt[section][bank];
537 	glablptr = bank_glabl[section][bank];
538 
539 	/* update the max bank counter */
540 	if (max_bank < bank)
541 		max_bank = bank;
542 
543 	/* output on last pass */
544 	if (pass == LAST_PASS) {
545 		loadlc(bank, 1);
546 		println();
547 	}
548 }
549 
550 
551 /* ----
552  * do_incbin()
553  * ----
554  * .incbin pseudo
555  */
556 
557 void
do_incbin(int * ip)558 do_incbin(int *ip)
559 {
560 	FILE *fp;
561 	char *p;
562 	char fname[128];
563 	int  size;
564 
565 	/* get file name */
566 	if (!getstring(ip, fname, 127))
567 		return;
568 
569 	/* get file extension */
570 	if ((p = strrchr(fname, '.')) != NULL) {
571 		if (!strchr(p, PATH_SEPARATOR)) {
572 			/* check if it's a mx file */
573 			if (!strcasecmp(p, ".mx")) {
574 				do_mx(fname);
575 				return;
576 			}
577 			/* check if it's a map file */
578 			if (!strcasecmp(p, ".fmp")) {
579 				if (pce_load_map(fname, 0))
580 					return;
581 			}
582 		}
583 	}
584 
585 	/* define label */
586 	labldef(loccnt, 1);
587 
588 	/* output */
589 	if (pass == LAST_PASS)
590 		loadlc(loccnt, 0);
591 
592 	/* open file */
593 	if ((fp = open_file(fname, "rb")) == NULL) {
594 		fatal_error("Can not open file!");
595 		return;
596 	}
597 
598 	/* get file size */
599 	fseek(fp, 0, SEEK_END);
600 	size = ftell(fp);
601 	fseek(fp, 0, SEEK_SET);
602 
603 	/* check if it will fit in the rom */
604 	if (((bank << 13) + loccnt + size) > rom_limit) {
605 		fclose(fp);
606 		error("ROM overflow!");
607 		return;
608 	}
609 
610 	/* load data on last pass */
611 	if (pass == LAST_PASS) {
612 		fread(&rom[bank][loccnt], 1, size, fp);
613 		memset(&map[bank][loccnt], section + (page << 5), size);
614 
615 		/* output line */
616 		println();
617 	}
618 
619 	/* close file */
620 	fclose(fp);
621 
622 	/* update bank and location counters */
623 	bank  += (loccnt + size) >> 13;
624 	loccnt = (loccnt + size) & 0x1FFF;
625 	if (bank > max_bank) {
626 		if (loccnt)
627 			max_bank = bank;
628 		else
629 			max_bank = bank - 1;
630 	}
631 
632 	/* size */
633 	if (lablptr) {
634 		lablptr->data_type = P_INCBIN;
635 		lablptr->data_size = size;
636 	}
637 	else {
638 		if (lastlabl) {
639 			if (lastlabl->data_type == P_INCBIN)
640 				lastlabl->data_size += size;
641 		}
642 	}
643 }
644 
645 
646 /* ----
647  * do_mx()
648  * ----
649  * load a mx file
650  */
651 
652 void
do_mx(char * fname)653 do_mx(char *fname)
654 {
655 	FILE *fp;
656 	char *ptr;
657 	char type;
658 	char line[256];
659 	unsigned char buffer[128];
660 	int data;
661 	int flag = 0;
662 	int size = 0;
663 	int cnt, addr, chksum;
664 	int i;
665 
666 	/* open the file */
667 	if ((fp = open_file(fname, "r")) == NULL) {
668 		fatal_error("Can not open file!");
669 		return;
670 	}
671 
672 	/* read loop */
673 	while (fgets(line, 254, fp) != NULL) {
674 		if (line[0] == 'S') {
675 			/* get record type */
676 			type = line[1];
677 
678 			/* error on unsupported records */
679 			if ((type != '2') && (type != '8')) {
680 				error("Unsupported S-record type!");
681 				return;
682 			}
683 
684 			/* get count and address */
685 			cnt  = htoi(&line[2], 2);
686 			addr = htoi(&line[4], 6);
687 
688 			if ((strlen(line) < 12) || (cnt < 4) || (addr == -1)) {
689 				error("Incorrect S-record line!");
690 				return;
691 			}
692 
693 			/* adjust count */
694 			cnt -= 4;
695 
696 			/* checksum */
697 			chksum = cnt + ((addr >> 16) & 0xFF) +
698 						   ((addr >> 8) & 0xFF) +
699 						   ((addr) & 0xFF) + 4;
700 
701 			/* get data */
702 			ptr = &line[10];
703 
704 			for (i = 0; i < cnt; i++) {
705 				data = htoi(ptr, 2);
706 				buffer[i] = data;
707 				chksum += data;
708 				ptr += 2;
709 
710 				if (data == -1) {
711 					error("Syntax error in a S-record line!");
712 					return;
713 				}
714 			}
715 
716 			/* checksum test */
717 			data = htoi(ptr, 2);
718 			chksum = (~chksum) & 0xFF;
719 
720 			if (data != chksum) {
721 				error("Checksum error!");
722 				return;
723 			}
724 
725 			/* end record */
726 			if (type == '8')
727 				break;
728 
729 			/* data record */
730 			if (type == '2') {
731 				/* set the location counter */
732 				if (addr & 0xFFFF0000) {
733 					error("Invalid address!");
734 					return;
735 				}
736 				page   = (addr >> 13) & 0x07;
737 				loccnt = (addr & 0x1FFF);
738 
739 				/* define label */
740 				if (flag == 0) {
741 					flag  = 1;
742 					labldef(loccnt, 1);
743 
744 					/* output */
745 					if (pass == LAST_PASS)
746 						loadlc(loccnt, 0);
747 				}
748 
749 				/* copy data */
750 				if (pass == LAST_PASS) {
751 					for (i = 0; i < cnt; i++)
752 						putbyte(loccnt + i, buffer[i]);
753 				}
754 
755 				/* update location counter */
756 				loccnt += cnt;
757 				size   += cnt;
758 			}
759 		}
760 	}
761 
762 	/* close file */
763 	fclose(fp);
764 
765 	/* define label */
766 	if (flag == 0) {
767 		labldef(loccnt, 1);
768 
769 		/* output */
770 		if (pass == LAST_PASS)
771 			loadlc(loccnt, 0);
772 	}
773 
774 	/* size */
775 	if (lablptr) {
776 		lablptr->data_type = P_INCBIN;
777 		lablptr->data_size = size;
778 	}
779 	else {
780 		if (lastlabl) {
781 			if (lastlabl->data_type == P_INCBIN)
782 				lastlabl->data_size += size;
783 		}
784 	}
785 
786 	/* output line */
787 	if (pass == LAST_PASS)
788 		println();
789 }
790 
791 
792 /* ----
793  * do_include()
794  * ----
795  * .include pseudo
796  */
797 
798 void
do_include(int * ip)799 do_include(int *ip)
800 {
801 	char fname[128];
802 
803 	/* define label */
804 	labldef(loccnt, 1);
805 
806 	/* get file name */
807 	if (!getstring(ip, fname, 127))
808 		return;
809 
810 	/* open file */
811 	if (open_input(fname) == -1) {
812 		fatal_error("Can not open file!");
813 		return;
814 	}
815 
816 	/* output line */
817 	if (pass == LAST_PASS)
818 		println();
819 }
820 
821 
822 /* ----
823  * do_rsset()
824  * ----
825  * .rsset pseudo
826  */
827 
828 void
do_rsset(int * ip)829 do_rsset(int *ip)
830 {
831 	/* define label */
832 	labldef(loccnt, 1);
833 
834 	/* get value */
835 	if (!evaluate(ip, ';'))
836 		return;
837 	if (value & 0xFFFF0000) {
838 		error("Address out of range!");
839 		return;
840 	}
841 
842 	/* set 'rs' base */
843 	rsbase = value;
844 
845 	/* output line */
846 	if (pass == LAST_PASS) {
847 		loadlc(rsbase, 1);
848 		println();
849 	}
850 }
851 
852 
853 /* ----
854  * do_rs()
855  * ----
856  * .rs pseudo
857  */
858 
859 void
do_rs(int * ip)860 do_rs(int *ip)
861 {
862 	/* define label */
863 	labldef(rsbase, 0);
864 
865 	/* get the number of bytes to reserve */
866 	if (!evaluate(ip, ';'))
867 		return;
868 
869 	/* ouput line */
870 	if (pass == LAST_PASS) {
871 		loadlc(rsbase, 1);
872 		println();
873 	}
874 
875 	/* update 'rs' base */
876 	rsbase += value;
877 	if (rsbase & 0xFFFF0000)
878 		error("Address out of range!");
879 }
880 
881 
882 /* ----
883  * do_ds()
884  * ----
885  * .ds pseudo
886  */
887 
888 void
do_ds(int * ip)889 do_ds(int *ip)
890 {
891 	int limit = 0;
892 	int addr;
893 
894 	/* define label */
895 	labldef(loccnt, 1);
896 
897 	/* get the number of bytes to reserve */
898 	if (!evaluate(ip, ';'))
899 		return;
900 
901 	/* section switch */
902 	switch (section) {
903 	case S_ZP:
904 		/* zero page section */
905 		limit = machine->zp_limit;
906 		break;
907 
908 	case S_BSS:
909 		/* ram section */
910 		limit = machine->ram_limit;
911 		break;
912 
913 	case S_CODE:
914 	case S_DATA:
915 		/* code and data sections */
916 		limit = 0x2000;
917 		break;
918 	}
919 
920 	/* check range */
921 	if ((loccnt + value) > limit) {
922 		error("Out of range!");
923 		return;
924 	}
925 
926 	/* update max counter for zp and bss sections */
927 	addr = loccnt + value;
928 
929 	switch (section) {
930 	case S_ZP:
931 		/* zero page */
932 		if (addr > max_zp)
933 			max_zp = addr;
934 		break;
935 
936 	case S_BSS:
937 		/* ram page */
938 		if (addr > max_bss)
939 			max_bss = addr;
940 		break;
941 	}
942 
943 	/* output line on last pass */
944 	if (pass == LAST_PASS) {
945 		switch (section) {
946 		case S_CODE:
947 		case S_DATA:
948 			memset(&rom[bank][loccnt], 0, value);
949 			memset(&map[bank][loccnt], section + (page << 5), value);
950 			if (bank > max_bank)
951 				max_bank = bank;
952 			break;
953 		}
954 		loadlc(loccnt, 0);
955 		println();
956 	}
957 
958 	/* update location counter */
959 	loccnt += value;
960 }
961 
962 
963 /* ----
964  * do_fail()
965  * ----
966  * .fail pseudo
967  */
968 
969 void
do_fail(int * ip)970 do_fail(int *ip)
971 {
972 	fatal_error("Compilation failed!");
973 }
974 
975 
976 /* ----
977  * do_section()
978  * ----
979  * .zp/.bss/.code/.data pseudo
980  */
981 
982 void
do_section(int * ip)983 do_section(int *ip)
984 {
985 	if (proc_ptr) {
986 		if (optype == S_DATA) {
987 			fatal_error("No data segment in procs!");
988 			return;
989 		}
990 	}
991 	if (section != optype) {
992 		/* backup current section data */
993 		section_bank[section] = bank;
994 		bank_glabl[section][bank] = glablptr;
995 		bank_loccnt[section][bank] = loccnt;
996 		bank_page[section][bank] = page;
997 
998 		/* change section */
999 		section = optype;
1000 
1001 		/* switch to the new section */
1002 		bank = section_bank[section];
1003 		page = bank_page[section][bank];
1004 		loccnt = bank_loccnt[section][bank];
1005 		glablptr = bank_glabl[section][bank];
1006 	}
1007 
1008 	/* output line */
1009 	if (pass == LAST_PASS) {
1010 		loadlc(loccnt + (page << 13), 1);
1011 		println();
1012 	}
1013 }
1014 
1015 
1016 /* ----
1017  * do_incchr()
1018  * ----
1019  * .inchr pseudo - convert a PCX to 8x8 character tiles
1020  */
1021 
1022 void
do_incchr(int * ip)1023 do_incchr(int *ip)
1024 {
1025 	unsigned char buffer[32];
1026 	unsigned int i, j;
1027 	unsigned int x, y, w, h;
1028 	unsigned int tx, ty;
1029 	int total = 0;
1030 	int size;
1031 
1032 	/* define label */
1033 	labldef(loccnt, 1);
1034 
1035 	/* output */
1036 	if (pass == LAST_PASS)
1037 		loadlc(loccnt, 0);
1038 
1039 	/* get args */
1040 	if (!pcx_get_args(ip))
1041 		return;
1042 	if (!pcx_parse_args(0, pcx_nb_args, &x, &y, &w, &h, 8))
1043 		return;
1044 
1045 	/* pack data */
1046 	for (i = 0; i < h; i++) {
1047 		for (j = 0; j < w; j++) {
1048 			/* tile coordinates */
1049 			tx = x + (j << 3);
1050 			ty = y + (i << 3);
1051 
1052 			/* get tile */
1053 			size   = pcx_pack_8x8_tile(buffer, tx, ty);
1054 			total += size;
1055 
1056 			/* store tile */
1057 			putbuffer(buffer, size);
1058 		}
1059 	}
1060 
1061 	/* size */
1062 	if (lablptr) {
1063 		lablptr->data_type = P_INCCHR;
1064 		lablptr->data_size = total;
1065 	}
1066 	else {
1067 		if (lastlabl) {
1068 			if (lastlabl->data_type == P_INCCHR)
1069 				lastlabl->data_size += total;
1070 		}
1071 	}
1072 
1073 	/* output */
1074 	if (pass == LAST_PASS)
1075 		println();
1076 }
1077 
1078 
1079 /* ----
1080  * do_opt()
1081  * ----
1082  * .opt pseudo - compilation options
1083  */
1084 
1085 void
do_opt(int * ip)1086 do_opt(int *ip)
1087 {
1088 	char c;
1089 	char flag;
1090 	char name[32];
1091 	int  opt;
1092 	int  i;
1093 
1094 	for (;;) {
1095 		/* skip spaces */
1096 		while (isspace(prlnbuf[*ip]))
1097 			(*ip)++;
1098 
1099 		/* get char */
1100 		c = prlnbuf[(*ip)++];
1101 
1102 		/* no option */
1103 		if (c == ',')
1104 			continue;
1105 
1106 		/* end of line */
1107 		if (c == ';' || c == '\0')
1108 			break;
1109 
1110 		/* extract option */
1111 		i = 0;
1112 		for (;;) {
1113 			if (c == ' ')
1114 				continue;
1115 			if (c == ',' || c == ';' || c == '\0')
1116 				break;
1117 			if (i > 31) {
1118 				error("Syntax error!");
1119 				return;
1120 			}
1121 			name[i++] = c;
1122 			c = prlnbuf[(*ip)++];
1123 		}
1124 
1125 		/* get option flag */
1126 		name[i] = '\0';
1127 		flag = name[--i];
1128 		name[i] = '\0';
1129 
1130 		/* search option */
1131 		if (!strcasecmp(name, "l"))
1132 			opt = OPT_LIST;
1133 		else if (!strcasecmp(name, "m"))
1134 			opt = OPT_MACRO;
1135 		else if (!strcasecmp(name, "w"))
1136 			opt = OPT_WARNING;
1137 		else if (!strcasecmp(name, "o"))
1138 			opt = OPT_OPTIMIZE;
1139 		else {
1140 			error("Unknown option!");
1141 			return;
1142 		}
1143 
1144 		/* set option */
1145 		if (flag == '+')
1146 			asm_opt[opt] = 1;
1147 		if (flag == '-')
1148 			asm_opt[opt] = 0;
1149 	}
1150 
1151 	/* output */
1152 	if (pass == LAST_PASS)
1153 		println();
1154 }
1155 
1156 
1157 /* ----
1158  * htoi()
1159  * ----
1160  */
1161 
1162 int
htoi(char * str,int nb)1163 htoi(char *str, int nb)
1164 {
1165 	char c;
1166 	int val;
1167 	int i;
1168 
1169 	val = 0;
1170 
1171 	for (i = 0; i < nb; i++) {
1172 		 c = toupper(str[i]);
1173 
1174 		if ((c >= '0') && (c <= '9'))
1175 			val = (val << 4) + (c - '0');
1176 		else if ((c >= 'A') && (c <= 'F'))
1177 			val = (val << 4) + (c - 'A' + 10);
1178 		else
1179 			return (-1);
1180 	}
1181 
1182 	/* ok */
1183 	return (val);
1184 }
1185 
1186