1 #include <stdio.h>
2 #include <string.h>
3 #include <ctype.h>
4 #include "defs.h"
5 #include "externs.h"
6 #include "protos.h"
7 
8 unsigned char auto_inc;
9 unsigned char auto_tag;
10 unsigned int  auto_tag_value;
11 
12 
13 /* ----
14  * class1()
15  * ----
16  * 1 byte, no operand field
17  */
18 
19 void
class1(int * ip)20 class1(int *ip)
21 {
22 	check_eol(ip);
23 
24 	/* update location counter */
25 	loccnt++;
26 
27 	/* generate code */
28 	if (pass == LAST_PASS) {
29 		/* opcode */
30 		putbyte(data_loccnt, opval);
31 
32 		/* output line */
33 		println();
34 	}
35 }
36 
37 
38 /* ----
39  * class2()
40  * ----
41  * 2 bytes, relative addressing
42  */
43 
44 void
class2(int * ip)45 class2(int *ip)
46 {
47 	unsigned int addr;
48 
49 	/* update location counter */
50 	loccnt += 2;
51 
52 	/* get destination address */
53 	if (!evaluate(ip, ';'))
54 		return;
55 
56 	/* generate code */
57 	if (pass == LAST_PASS) {
58 		/* opcode */
59 		putbyte(data_loccnt, opval);
60 
61 		/* calculate branch offset */
62 		addr = value - (loccnt + (page << 13));
63 
64 		/* check range */
65 		if (addr > 0x7F && addr < 0xFFFFFF80) {
66 			error("Branch address out of range!");
67 			return;
68 		}
69 
70 		/* offset */
71 		putbyte(data_loccnt+1, addr);
72 
73 		/* output line */
74 		println();
75 	}
76 }
77 
78 
79 /* ----
80  * class3()
81  * ----
82  * 2 bytes, inherent addressing
83  */
84 
85 void
class3(int * ip)86 class3(int *ip)
87 {
88 	check_eol(ip);
89 
90 	/* update location counter */
91 	loccnt += 2;
92 
93 	/* generate code */
94 	if (pass == LAST_PASS) {
95 		/* opcodes */
96 		putbyte(data_loccnt, opval);
97 		putbyte(data_loccnt+1, optype);
98 
99 		/* output line */
100 		println();
101 	}
102 }
103 
104 
105 /* ----
106  * class4()
107  * ----
108  * various addressing modes
109  */
110 
111 void
class4(int * ip)112 class4(int *ip)
113 {
114 	char buffer[32];
115 	char c;
116 	int len, mode;
117 	int	i;
118 
119 	/* skip spaces */
120 	while (isspace(prlnbuf[*ip]))
121 		(*ip)++;
122 
123 	/* low/high byte prefix string */
124 	if (isalpha(prlnbuf[*ip])) {
125 		len = 0;
126 		i = *ip;
127 
128 		/* extract string */
129 		for (;;) {
130 			c = prlnbuf[i];
131 			if (c == '\0' || c == ' ' || c == '\t' || c == ';')
132 				break;
133 			if ((!isalpha(c) && c != '_') || (len == 31)) {
134 				len = 0;
135 				break;
136 			}
137 			buffer[len++] = c;
138 			i++;
139 		}
140 
141 		/* check */
142 		if (len) {
143 			buffer[len] = '\0';
144 
145 			if (strcasecmp(buffer, "low_byte") == 0) {
146 				opext = 'L';
147 				*ip = i;
148 			}
149 			if (strcasecmp(buffer, "high_byte") == 0) {
150 				opext = 'H';
151 				*ip = i;
152 			}
153 		}
154 	}
155 
156 	/* get operand */
157 	mode = getoperand(ip, opflg, ';');
158 	if (!mode)
159 		return;
160 
161 	/* make opcode */
162 	if (pass == LAST_PASS) {
163 		for (i = 0; i < 32; i++) {
164 			if (mode & (1 << i))
165 				break;
166 		}
167 		opval += opvaltab[optype][i];
168 	}
169 
170 	/* auto-tag */
171 	if (auto_tag) {
172 		if (pass == LAST_PASS) {
173 			putbyte(loccnt, 0xA0);
174 			putbyte(loccnt+1, auto_tag_value);
175 		}
176 		loccnt += 2;
177 	}
178 
179 	/* generate code */
180 	switch(mode) {
181 	case ACC:
182 		/* one byte */
183 		if (pass == LAST_PASS)
184 			putbyte(loccnt, opval);
185 
186 		loccnt++;
187 		break;
188 
189 	case IMM:
190 	case ZP:
191 	case ZP_X:
192 	case ZP_Y:
193 	case ZP_IND:
194 	case ZP_IND_X:
195 	case ZP_IND_Y:
196 		/* two bytes */
197 		if (pass == LAST_PASS) {
198 			putbyte(loccnt, opval);
199 			putbyte(loccnt+1, value);
200 		}
201 		loccnt += 2;
202 		break;
203 
204 	case ABS:
205 	case ABS_X:
206 	case ABS_Y:
207 	case ABS_IND:
208 	case ABS_IND_X:
209 		/* three bytes */
210 		if (pass == LAST_PASS) {
211 			putbyte(loccnt, opval);
212 			putword(loccnt+1, value);
213 		}
214 		loccnt += 3;
215 		break;
216 	}
217 
218 	/* auto-increment */
219 	if (auto_inc) {
220 		if (pass == LAST_PASS)
221 			putbyte(loccnt, auto_inc);
222 
223 		loccnt += 1;
224 	}
225 
226 	/* output line */
227 	if (pass == LAST_PASS)
228 		println();
229 }
230 
231 
232 /* ----
233  * class5()
234  * ----
235  * 3 bytes, zp/relative addressing
236  */
237 
238 void
class5(int * ip)239 class5(int *ip)
240 {
241 	int	zp;
242 	unsigned int addr;
243 	int mode;
244 
245 	/* update location counter */
246 	loccnt += 3;
247 
248 	/* get first operand */
249 	mode = getoperand(ip, ZP, ',');
250 	zp   = value;
251 	if (!mode)
252 		return;
253 
254 	/* get second operand */
255 	mode = getoperand(ip, ABS, ';');
256 	if (!mode)
257 		return;
258 
259 	/* generate code */
260 	if (pass == LAST_PASS) {
261 		/* opcodes */
262 		putbyte(data_loccnt, opval);
263 		putbyte(data_loccnt+1, zp);
264 
265 		/* calculate branch offset */
266 		addr = value - (loccnt + (page << 13));
267 
268 		/* check range */
269 		if (addr > 0x7F && addr < 0xFFFFFF80) {
270 			error("Branch address out of range!");
271 			return;
272 		}
273 
274 		/* offset */
275 		putbyte(data_loccnt+2, addr);
276 
277 		/* output line */
278 		println();
279 	}
280 }
281 
282 
283 /* ----
284  * class6()
285  * ----
286  * 7 bytes, src/dest/length
287  */
288 
289 void
class6(int * ip)290 class6(int *ip)
291 {
292 	int	i;
293 	int addr[3];
294 
295 	/* update location counter */
296 	loccnt +=7;
297 
298 	/* get operands */
299     for (i = 0; i < 3; i++) {
300 		if (!evaluate(ip, (i < 2) ? ',' : ';'))
301 			return;
302 		if (pass == LAST_PASS) {
303 			if (value & 0xFFFF0000) {
304 				error("Operand size error!");
305 				return;
306 			}
307 		}
308 	    addr[i] = value;
309 	}
310 
311 	/* generate code */
312 	if (pass == LAST_PASS) {
313 		/* opcodes */
314 		putbyte(data_loccnt, opval);
315 		putword(data_loccnt+1, addr[0]);
316 		putword(data_loccnt+3, addr[1]);
317 		putword(data_loccnt+5, addr[2]);
318 
319 		/* output line */
320 		println();
321 	}
322 }
323 
324 
325 /* ----
326  * class7()
327  * ----
328  * TST instruction
329  */
330 
331 void
class7(int * ip)332 class7(int *ip)
333 {
334 	int mode;
335 	int addr, imm;
336 
337 	/* get first operand */
338 	mode = getoperand(ip, IMM, ',');
339 	imm  = value;
340 	if (!mode)
341 		return;
342 
343 	/* get second operand */
344 	mode = getoperand(ip, (ZP | ZP_X | ABS | ABS_X), ';');
345 	addr = value;
346 	if (!mode)
347 		return;
348 
349 	/* make opcode */
350 	if (mode & (ZP | ZP_X))
351 		opval = 0x83;
352 	if (mode & (ABS | ABS_X))
353 		opval = 0x93;
354 	if (mode & (ZP_X | ABS_X))
355 		opval+= 0x20;
356 
357 	/* generate code */
358 	if (pass == LAST_PASS) {
359 		/* opcodes */
360 		putbyte(loccnt, opval);
361 		putbyte(loccnt+1, imm);
362 
363 		if (mode & (ZP | ZP_X))
364 			/* zero page */
365 			putbyte(loccnt+2, addr);
366 		else
367 			/* absolute */
368 			putword(loccnt+2, addr);
369 	}
370 
371 	/* update location counter */
372 	if (mode & (ZP | ZP_X))
373 		loccnt += 3;
374 	else
375 		loccnt += 4;
376 
377 	/* auto-increment */
378 	if (auto_inc) {
379 		if (pass == LAST_PASS)
380 			putbyte(loccnt, auto_inc);
381 
382 		loccnt += 1;
383 	}
384 
385 	/* output line */
386 	if (pass == LAST_PASS)
387 		println();
388 }
389 
390 
391 /* ----
392  * class8()
393  * ----
394  * TAM/TMA instruction
395  */
396 
397 void
class8(int * ip)398 class8(int *ip)
399 {
400 	int mode;
401 
402 	/* update location counter */
403 	loccnt += 2;
404 
405 	/* get operand */
406 	mode = getoperand(ip, IMM, ';');
407 	if (!mode)
408 		return;
409 
410 	/* generate code */
411 	if (pass == LAST_PASS) {
412 		/* check page index */
413 		if (value & 0xF8) {
414 			error("Incorrect page index!");
415 			return;
416 		}
417 
418 		/* opcodes */
419 		putbyte(data_loccnt, opval);
420 		putbyte(data_loccnt+1, (1 << value));
421 
422 		/* output line */
423 		println();
424 	}
425 }
426 
427 
428 /* ----
429  * class9()
430  * ----
431  * RMB/SMB instructions
432  */
433 
434 void
class9(int * ip)435 class9(int *ip)
436 {
437 	int bit;
438 	int mode;
439 
440 	/* update location counter */
441 	loccnt += 2;
442 
443 	/* get the bit index */
444 	mode = getoperand(ip, IMM, ',');
445 	bit  = value;
446 	if (!mode)
447 		return;
448 
449 	/* get the zero page address */
450 	mode = getoperand(ip, ZP, ';');
451 	if (!mode)
452 		return;
453 
454 	/* generate code */
455 	if (pass == LAST_PASS) {
456 		/* check bit number */
457 		if (bit > 7) {
458 			error("Incorrect bit number!");
459 			return;
460 		}
461 
462 		/* opcodes */
463 		putbyte(data_loccnt, opval + (bit << 4));
464 		putbyte(data_loccnt+1, value);
465 
466 		/* output line */
467 		println();
468 	}
469 }
470 
471 
472 /* ----
473  * class10()
474  * ----
475  * BBR/BBS instructions
476  */
477 
478 void
class10(int * ip)479 class10(int *ip)
480 {
481 	int bit;
482 	int zp;
483 	int mode;
484 	unsigned int addr;
485 
486 	/* update location counter */
487 	loccnt += 3;
488 
489 	/* get the bit index */
490 	mode = getoperand(ip, IMM, ',');
491 	bit  = value;
492 	if (!mode)
493 		return;
494 
495 	/* get the zero page address */
496 	mode = getoperand(ip, ZP, ',');
497 	zp   = value;
498 	if (!mode)
499 		return;
500 
501 	/* get the jump address */
502 	mode = getoperand(ip, ABS, ';');
503 	if (!mode)
504 		return;
505 
506 	/* generate code */
507 	if (pass == LAST_PASS) {
508 		/* check bit number */
509 		if (bit > 7) {
510 			error("Incorrect bit number!");
511 			return;
512 		}
513 
514 		/* opcodes */
515 		putbyte(data_loccnt, opval + (bit << 4));
516 		putbyte(data_loccnt+1, zp);
517 
518 		/* calculate branch offset */
519 		addr = value - (loccnt + (page << 13));
520 
521 		/* check range */
522 		if (addr > 0x7F && addr < 0xFFFFFF80) {
523 			error("Branch address out of range!");
524 			return;
525 		}
526 
527 		/* offset */
528 		putbyte(data_loccnt+2, addr);
529 
530 		/* output line */
531 		println();
532 	}
533 }
534 
535 
536 /* ----
537  * getoperand()
538  * ----
539  */
540 
541 int
getoperand(int * ip,int flag,int last_char)542 getoperand(int *ip, int flag, int last_char)
543 {
544 	unsigned int tmp;
545 	char c;
546 	int code;
547 	int mode;
548 	int pos;
549 	int end;
550 
551 	/* init */
552 	auto_inc = 0;
553 	auto_tag = 0;
554 
555 	/* skip spaces */
556 	while (isspace(prlnbuf[*ip]))
557 		(*ip)++;
558 
559 	/* check addressing mode */
560 	switch (prlnbuf[*ip]) {
561 	case '\0':
562 	case ';':
563 		/* no operand */
564 		error("Operand missing!");
565 		return (0);
566 
567 	case 'A':
568 	case 'a':
569 		/* accumulator */
570 		c = prlnbuf[(*ip)+1];
571 		if (isspace(c) || c == '\0' || c == ';' || c == ',') {
572 			mode = ACC;
573 			(*ip)++;
574 			break;
575 		}
576 
577 	default:
578 		/* other */
579 		switch(prlnbuf[*ip]) {
580 		case '#':
581 			/* immediate */
582 			mode = IMM;
583 			(*ip)++;
584 			break;
585 
586 		case '<':
587 			/* zero page */
588 			mode = ZP | ZP_X | ZP_Y;
589 			(*ip)++;
590 			break;
591 
592 		case '[':
593 			/* indirect */
594 			mode = ABS_IND | ABS_IND_X | ZP_IND | ZP_IND_X | ZP_IND_Y;
595 			(*ip)++;
596 			break;
597 
598 		default:
599 			/* absolute */
600 			mode = ABS | ABS_X | ABS_Y;
601 			break;
602 		}
603 
604 		/* get value */
605 		if (!evaluate(ip, 0))
606 			return (0);
607 
608 		/* check addressing mode */
609 		code = 0;
610 		end = 0;
611 		pos = 0;
612 
613 		while (!end) {
614 			c = prlnbuf[*ip];
615 			if (c == ';' || c == '\0')
616 				break;
617 			switch (toupper(c)) {
618 			case ',':		/* , = 5 */
619 				if (!pos)
620 					 pos = *ip;
621 				else {
622 					end = 1;
623 					break;
624 				}
625 				code++;
626 			case '+':		/* + = 4 */
627 				code++;
628 			case ']':		/* ] = 3 */
629 				code++;
630 				if (prlnbuf[*ip + 1] == '.') {
631 					end = 1;
632 					break;
633 				}
634 			case 'X':		/* X = 2 */
635 				code++;
636 			case 'Y':		/* Y = 1 */
637 				code++;
638 				code <<= 4;
639 			case ' ':
640 			case '\t':
641 				(*ip)++;
642 				break;
643 			default:
644 				code = 0xFFFFFF;
645 				end  = 1;
646 				break;
647 			}
648 		}
649 
650 		/* absolute, zp, or immediate */
651 		if (code == 0x000000)
652 			mode &= (ABS | ZP | IMM);
653 
654 		/* indirect */
655 		else if (code == 0x000030)
656 			mode &= (ZP_IND | ABS_IND);		// ]
657 
658 		/* indexed modes */
659 		else if (code == 0x000510)
660 			mode &= (ABS_Y | ZP_Y);			// ,Y
661 		else if (code == 0x000520)
662 			mode &= (ABS_X | ZP_X);			// ,X
663 		else if (code == 0x005230)
664 			mode &= (ZP_IND_X | ABS_IND_X);	// ,X]
665 		else if (code == 0x003510)
666 			mode &= (ZP_IND_Y);				// ],Y
667 		else if (code == 0x000001) {
668 			mode &= (ZP_IND_Y);				// ].tag
669 		  (*ip) += 2;
670 
671 			/* get tag */
672 			tmp = value;
673 
674 			if (!evaluate(ip, 0))
675 				return (0);
676 
677 			/* ok */
678 			auto_tag = 1;
679 			auto_tag_value = value;
680 			value = tmp;
681 		}
682 		/* indexed modes with post-increment */
683 		else if (code == 0x051440) {
684 			mode &= (ABS_Y | ZP_Y);			// ,Y++
685 			auto_inc = 0xC8;
686 		}
687 		else if (code == 0x052440) {
688 			mode &= (ABS_X | ZP_X);			// ,X++
689 			auto_inc = 0xE8;
690 		}
691 		else if (code == 0x351440) {
692 			mode &= (ZP_IND_Y);				// ],Y++
693 			auto_inc = 0xC8;
694 		}
695 
696 		/* absolute, zp, or immediate (or error) */
697 		else {
698 			mode &= (ABS | ZP | IMM);
699 			if (pos)
700 				*ip = pos;
701 		}
702 
703 		/* check value on last pass */
704 		if (pass == LAST_PASS) {
705 			/* zp modes */
706 			if (mode & (ZP | ZP_X | ZP_Y | ZP_IND | ZP_IND_X | ZP_IND_Y) & flag) {
707 				/* extension stuff */
708 				if (opext && !auto_inc) {
709 					if (mode & (ZP_IND | ZP_IND_X | ZP_IND_Y))
710 						error("Instruction extension not supported in indirect modes!");
711 					if (opext == 'H')
712 						value++;
713 				}
714 				/* check address validity */
715 				if ((value & 0xFFFFFF00) && ((value & 0xFFFFFF00) != machine->ram_base))
716 					error("Incorrect zero page address!");
717 			}
718 
719 			/* immediate mode */
720 			else if (mode & (IMM) & flag) {
721 				/* extension stuff */
722 				if (opext == 'L')
723 					value = (value & 0xFF);
724 				else if (opext == 'H')
725 					value = (value & 0xFF00) >> 8;
726 				else {
727 					/* check value validity */
728 					if ((value > 0xFF) && (value < 0xFFFFFF00))
729 						error("Incorrect immediate value!");
730 				}
731 			}
732 
733 			/* absolute modes */
734 			else if (mode & (ABS | ABS_X | ABS_Y | ABS_IND | ABS_IND_X) & flag) {
735 				/* extension stuff */
736 				if (opext && !auto_inc) {
737 					if (mode & (ABS_IND | ABS_IND_X))
738 						error("Instruction extension not supported in indirect modes!");
739 					if (opext == 'H')
740 						value++;
741 				}
742 				/* check address validity */
743 				if (value & 0xFFFF0000)
744 					error("Incorrect absolute address!");
745 			}
746 		}
747 		break;
748 	}
749 
750 	/* compare addressing mode */
751 	mode &= flag;
752 	if (!mode) {
753 		error("Incorrect addressing mode!");
754 		return (0);
755 	}
756 
757 	/* skip spaces */
758 	while (isspace(prlnbuf[*ip]))
759 		(*ip)++;
760 
761 	/* get last char */
762 	c = prlnbuf[*ip];
763 
764 	/* check if it's what the user asked for */
765 	switch (last_char) {
766 	case ';':
767 		/* last operand */
768 		if (c != ';' && c != '\0') {
769 			error("Syntax error!");
770 			return (0);
771 		}
772 		(*ip)++;
773 		break;
774 
775 	case ',':
776 		/* need more operands */
777 		if (c != ',') {
778 			error("Operand missing!");
779 			return (0);
780 		}
781 		(*ip)++;
782 		break;
783 	}
784 
785 	/* ok */
786 	return (mode);
787 }
788 
789 
790 /* ----
791  * getstring()
792  * ----
793  * get a string from prlnbuf
794  */
795 
796 int
getstring(int * ip,char * buffer,int size)797 getstring(int *ip, char *buffer, int size)
798 {
799 	char c;
800 	int i;
801 
802 	/* skip spaces */
803 	while (isspace(prlnbuf[*ip]))
804 		(*ip)++;
805 
806 	/* string must be enclosed */
807 	if (prlnbuf[(*ip)++] != '\"') {
808 		error("Incorrect string syntax!");
809 		return (0);
810 	}
811 
812 	/* get string */
813 	i = 0;
814 	for (;;) {
815 		c = prlnbuf[(*ip)++];
816 		if (c == '\"')
817 			break;
818 		if (i >= size) {
819 			error("String too long!");
820 			return (0);
821 		}
822 		buffer[i++] = c;
823 	}
824 
825 	/* end the string */
826 	buffer[i] = '\0';
827 
828 	/* skip spaces */
829 	while (isspace(prlnbuf[*ip]))
830 		(*ip)++;
831 
832 	/* ok */
833 	return (1);
834 }
835 
836