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