struct / union in initializer, RFE #901.
[sdcc.git] / sdcc / sdas / asgb / gbmch.c
blob5dda36a1e784246f41f4147fb0951fb9a4c59477
1 /* gbmch.c */
3 /*
4 * Copyright (C) 1989-2021 Alan R. Baldwin
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * Alan R. Baldwin
21 * 721 Berkeley St.
22 * Kent, Ohio 44240
26 * xerr messages Copyright (C) 1989-2021 Alan R. Baldwin
27 * from ASxxxx 5.40
28 * Things missing that exist in 5.40:
29 * .rel format
30 * cycle counting
34 * Extensions: P. Felber
36 * they seem to be:
37 * ldhl
38 * lda
41 /* Gameboy mods by Roger Ivie (ivie at cc dot usu dot edu); see gb.h for more info
44 #include "asxxxx.h"
45 #include "gb.h"
47 char *cpu = "GameBoy";
48 char *dsft = "asm";
50 char imtab[3] = { 0x46, 0x56, 0x5E };
53 * Opcode Cycle Definitions
55 #define OPCY_SDP ((char) (0xFF))
56 #define OPCY_ERR ((char) (0xFE))
58 /* OPCY_NONE ((char) (0x80)) */
59 /* OPCY_MASK ((char) (0x7F)) */
61 #define UN ((char) (OPCY_NONE | 0x00))
62 #define P2 ((char) (OPCY_NONE | 0x01))
65 * GB Opcode Cycle Pages
68 static char gbpg1[256] = {
69 /*--*--* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
70 /*--*--* - - - - - - - - - - - - - - - - */
71 /*00*/ 4,12, 8, 8, 4, 4, 8, 4,20, 8, 8, 8, 4, 4, 8, 4,
72 /*10*/ 4,12, 8, 8, 4, 4, 8, 4,12, 8, 8, 8, 4, 4, 8, 4,
73 /*20*/ 12,12, 8, 8, 4, 4, 8, 4,12, 8, 8, 8, 4, 4, 8, 4,
74 /*30*/ 12,12, 8, 8,12,12,12, 4,12, 8, 8, 8, 4, 4, 8, 4,
75 /*40*/ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
76 /*50*/ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
77 /*60*/ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
78 /*70*/ 8, 8, 8, 8, 8, 8, 4, 8, 4, 4, 4, 4, 4, 4, 8, 4,
79 /*80*/ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
80 /*90*/ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
81 /*A0*/ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
82 /*B0*/ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
83 /*C0*/ 20,12,16,16,24,16, 8,16,20,16,16,P2,24,24, 8,16,
84 /*D0*/ 20,12,16,UN,24,16, 8,16,20,16,16,UN,24,UN, 8,16,
85 /*E0*/ 12,12, 8,UN,UN,16, 8,16,16, 4,16,UN,UN,UN, 8,16,
86 /*F0*/ 12,12, 8, 4,UN,16, 8,16,12, 8,16, 4,UN,UN, 8,16
89 static char gbpg2[256] = { /* P2 == CB */
90 /*--*--* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
91 /*--*--* - - - - - - - - - - - - - - - - */
92 /*00*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
93 /*10*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
94 /*20*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
95 /*30*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
96 /*40*/ 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
97 /*50*/ 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
98 /*60*/ 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
99 /*70*/ 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
100 /*80*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
101 /*90*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
102 /*A0*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
103 /*B0*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
104 /*C0*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
105 /*D0*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
106 /*E0*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
107 /*F0*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8
110 static char *gbPage[2] = {
111 gbpg1, gbpg2
115 * Process a machine op.
117 VOID
118 machine(mp)
119 struct mne *mp;
121 int op, t1, t2;
122 struct expr e1, e2;
123 int rf, v1, v2;
124 int d,c,i,th,tl,oops; /* for dealing with .tile */
126 clrexpr(&e1);
127 clrexpr(&e2);
128 op = (int) mp->m_valu;
129 rf = mp->m_type;
130 switch (rf) {
132 case S_INH1:
133 outab(op);
134 break;
136 case S_RET:
137 if (more()) {
138 if ((v1 = admode(CND)) != 0) {
139 outab(op | (v1<<3));
140 } else {
141 xerr('q', "Condition codes are NZ, Z, NC, and C.");
143 } else {
144 outab(0xC9);
146 break;
148 case S_PUSH:
149 if (admode(R16X)) {
150 outab(op+0x30);
151 break;
152 } else
153 if ((v1 = admode(R16)) != 0 && (v1 &= 0xFF) != SP) {
154 outab(op | (v1<<4));
155 break;
157 xerr('a', "Register SP is invalid.");
158 break;
160 case S_RST:
161 v1 = (int) absexpr();
162 if (v1 & ~0x38) {
163 xerr('a', "Valid values are N * 0x08, N = 0 -> 7.");
164 v1 = 0;
166 outab(op|v1);
167 break;
169 case S_IM:
170 expr(&e1, 0);
171 abscheck(&e1);
172 if (e1.e_addr > 2) {
173 xerr('a', "Valid values are 0 -> 2.");
174 e1.e_addr = 0;
176 outab(op);
177 outab(imtab[(int) e1.e_addr]);
178 break;
180 case S_BIT:
181 expr(&e1, 0);
182 t1 = 0;
183 v1 = (int) e1.e_addr;
184 if (v1 > 7) {
185 ++t1;
186 v1 &= 0x07;
188 op |= (v1<<3);
189 comma(1);
190 addr(&e2);
191 abscheck(&e1);
192 if (genop(0xCB, op, &e2, 0) || t1)
193 xerr('a', "Invalid Addressing Mode.");
194 break;
196 case S_RL:
197 t1 = 0;
198 t2 = addr(&e2);
199 if (more()) {
200 if ((t2 != S_R8) || (e2.e_addr != A))
201 ++t1;
202 comma(1);
203 clrexpr(&e2);
204 t2 = addr(&e2);
206 if (genop(0xCB, op, &e2, 0) || t1)
207 xerr('a', "Invalid Addressing Mode.");
208 break;
210 /* TODO: where is S_SWAP? */
212 case S_AND:
213 case S_SUB:
214 t1 = 0;
215 t2 = addr(&e2);
216 if (more()) {
217 if ((t2 != S_R8) || (e2.e_addr != A))
218 ++t1;
219 comma(1);
220 clrexpr(&e2);
221 t2 = addr(&e2);
223 if (genop(0, op, &e2, 1) || t1)
224 xerr('a', "Invalid Addressing Mode.");
225 break;
227 case S_ADC:
228 case S_SBC:
229 t1 = addr(&e1);
230 t2 = 0;
231 if (more()) {
232 comma(1);
233 t2 = addr(&e2);
235 if (t2 == 0) {
236 if (genop(0, op, &e1, 1))
237 xerr('a', "Invalid Addressing Mode.");
238 break;
240 if ((t1 == S_R8) && (e1.e_addr == A)) {
241 if (genop(0, op, &e2, 1))
242 xerr('a', "Invalid Addressing Mode.");
243 break;
245 xerr('a', "Invalid Addressing Mode.");
246 break;
248 case S_ADD:
249 t1 = addr(&e1);
250 t2 = 0;
251 if (more()) {
252 comma(1);
253 t2 = addr(&e2);
255 if (t2 == 0) {
256 if (genop(0, op, &e1, 1))
257 xerr('a', "Invalid Addressing Mode.");
258 break;
260 if ((t1 == S_R8) && (e1.e_addr == A)) {
261 if (genop(0, op, &e2, 1))
262 xerr('a', "Invalid Addressing Mode.");
263 break;
265 if ((t1 == S_R16) && (t2 == S_R16)) {
266 if( rf == S_ADD ) {
267 op = 0x09;
268 v1 = (int) e1.e_addr;
269 v2 = (int) e2.e_addr;
270 if ((v1 == HL) && (v2 <= SP)) {
271 outab(op | (v2 << 4));
272 break;
277 * 0xE8 : ADD SP,#n
279 if ((t1 == S_R16) && (t2 == S_IMMED)) {
280 if (rf != S_ADD ) {
281 xerr('a', "ADC, SUB, and SBC are invalid.");
282 break;
284 if( e1.e_addr == SP ) {
285 outab(0xE8);
286 outrb(&e2,0);
287 break;
290 xerr('a', "Invalid Addressing Mode.");
291 break;
293 case S_LD:
294 t1 = addr(&e1);
295 comma(1);
296 t2 = addr(&e2);
298 if (t1 == S_R8) {
299 v1 = (int) (e1.e_addr<<3);
300 if (genop(0, op | v1, &e2, 0) == 0)
301 break;
302 if (t2 == S_IMMED) {
303 outab(v1 | 0x06);
304 outrb(&e2,0);
305 break;
309 v1 = (int) e1.e_addr;
310 v2 = (int) e2.e_addr;
312 if ((t1 == S_R16) && (t2 == S_IMMED)) {
313 outab(0x01 | (v1<<4));
314 outrw(&e2, 0);
315 break;
317 if ((t2 == S_R8) && (t1 == S_IDHL)) {
318 outab(0x70|v2);
319 if (t1 != S_IDHL)
320 outrb(&e1, 0);
321 break;
323 if ((t2 == S_IMMED) && (t1 == S_IDHL)) {
324 outab(0x36);
325 if (t1 != S_IDHL)
326 outrb(&e1, 0);
327 outrb(&e2, 0);
328 break;
330 if ((t1 == S_R16) && (v1 == SP)) {
331 if ((t2 == S_R16) && (v2 == HL)) {
332 outab(0xF9);
333 break;
336 if ((t1 == S_R8) && (v1 == A)) {
337 if ((t2 == S_IDBC) || (t2 == S_IDDE)) {
338 outab(0x0A | ((t2-S_INDR)<<4));
339 break;
342 if ((t2 == S_R8) && (v2 == A)) {
343 if ((t1 == S_IDBC) || (t1 == S_IDDE)) {
344 outab(0x02 | ((t1-S_INDR)<<4));
345 break;
349 * 0x08 : LD (nn),SP
351 if ((t1 == S_INDM) && (t2 == S_R16) && (v2 == SP)) {
352 outab(0x08);
353 outrw(&e1, 0);
354 break;
357 * 0xEA : LD (nn),A
358 * 0xFA : LD A,(nn)
360 if ((t1 == S_INDM) && (t2 == S_R8) && (v2 == A)) {
361 outab(0xEA);
362 outrw(&e1, 0);
363 break;
365 if ((t2 == S_INDM) && (t1 == S_R8) && (v1 == A)) {
366 outab(0xFA);
367 outrw(&e2, 0);
368 break;
371 * 0x32 : LD (HL-),A
372 * 0x3A : LD A,(HL-)
374 if ((t1 == S_R8) && (v1 == A) && (t2 == S_IDHLD)) {
375 outab(0x3A);
376 break;
378 if ((t2 == S_R8) && (v2 == A) && (t1 == S_IDHLD)) {
379 outab(0x32);
380 break;
383 * 0x22 : LD (HL+),A
384 * 0x2A : LD A,(HL+)
386 if ((t1 == S_R8) && (v1 == A) && (t2 == S_IDHLI)) {
387 outab(0x2A);
388 break;
390 if ((t2 == S_R8) && (v2 == A) && (t1 == S_IDHLI)) {
391 outab(0x22);
392 break;
394 xerr('a', "Invalid Addressing Mode.");
395 break;
397 /* TODO: find out where this handled in upstream */
398 case S_STOP: /* 0x10 */
400 * 0x10 : STOP
402 outab(op);
403 outab(0x00);
404 break;
406 case S_LDA: /* 0xE8 */ /* extension */
408 * 0xE8 : LDA SP,#n(SP)
409 * 0xF8 : LDA HL,#n(SP)
411 t1 = addr(&e1);
412 comma(1);
413 t2 = addr(&e2);
414 if ((t1 == S_R16) && (e1.e_addr == SP) && (t2 == S_INDR+SP)) {
415 outab(0xE8);
416 outrb(&e2,0);
417 break;
419 if ((t1 == S_R16) && (e1.e_addr == HL) && (t2 == S_INDR+SP)) {
420 outab(0xF8);
421 outrb(&e2,0);
422 break;
424 xerr('a', "Invalid Addressing Mode.");
425 break;
427 case S_LDHL: /* 0xF8 */ /* extension */
429 * 0xF8 : LDHL SP,#n
431 t1 = addr(&e1);
432 comma(1);
433 t2 = addr(&e2);
434 if ((t1 == S_R16) && (e1.e_addr == SP) && (t2 == S_IMMED)) {
435 outab(0xF8);
436 outrb(&e2,0);
437 break;
439 xerr('a', "Invalid Addressing Mode.");
440 break;
442 case S_DEC:
443 case S_INC:
444 t1 = addr(&e1);
445 v1 = (int) e1.e_addr;
446 if (t1 == S_R8) {
447 outab(op|(v1<<3));
448 break;
450 if (t1 == S_IDHL) {
451 outab(op|0x30);
452 break;
454 if (t1 == S_R16) {
455 if (rf == S_INC) {
456 outab(0x03|(v1<<4));
457 break;
459 if (rf == S_DEC) {
460 outab(0x0B|(v1<<4));
461 break;
464 xerr('a', "Invalid Addressing Mode.");
465 break;
467 case S_JR:
468 if ((v1 = admode(CND)) != 0 ) {
469 if ((v1 &= 0xFF) <= 0x03) {
470 op += (v1+1)<<3;
471 } else {
472 xerr('q', "Condition codes are NZ, Z, NC, and C.");
474 comma(1);
476 expr(&e2, 0);
477 outab(op);
478 if (mchpcr(&e2)) {
479 v2 = (int) (e2.e_addr - dot.s_addr - 1);
480 if (pass == 2 && ((v2 < -128) || (v2 > 127)))
481 xerr('a', "Branching Range Exceeded.");
482 outab(v2);
483 } else {
484 outrb(&e2, R_PCR);
486 if (e2.e_mode != S_USER)
487 rerr();
488 break;
490 case S_CALL:
491 if ((v1 = admode(CND)) != 0) {
492 op |= (v1&0xFF)<<3;
493 comma(1);
494 } else {
495 op = 0xCD;
497 expr(&e1, 0);
498 outab(op);
499 outrw(&e1, 0);
500 break;
502 case S_JP:
503 if ((v1 = admode(CND)) != 0) {
504 op |= (v1&0xFF)<<3;
505 comma(1);
506 expr(&e1, 0);
507 outab(op);
508 outrw(&e1, 0);
509 break;
511 t1 = addr(&e1);
512 if (t1 == S_USER) {
513 outab(0xC3);
514 outrw(&e1, 0);
515 break;
517 if ((e1.e_addr == 0) && (t1 == S_IDHL)) {
518 outab(0xE9);
519 break;
521 xerr('a', "Invalid Addressing Mode.");
522 break;
524 case S_LDH:
526 * 0xE0 : LDH (n),A = LD ($FF00+n),A
527 * 0xE2 : LDH (C),A = LD ($FF00+C),A
528 * 0xF0 : LDH A,(n) = LD A,($FF00+n)
529 * 0xF2 : LDH A,(C) = LD A,($FF00+C)
532 t1 = addr(&e1);
533 comma(1);
534 t2 = addr(&e2);
535 v1 = (int) e1.e_addr;
536 v2 = (int) e2.e_addr;
538 if ((t1 == S_R8) && (v1 == A) && (t2 == S_INDM)) {
539 outab(0xF0);
540 outrb(&e2, 0);
541 break;
543 if ((t2 == S_R8) && (v2 == A) && (t1 == S_INDM)) {
544 outab(0xE0);
545 outrb(&e1, 0);
546 break;
548 if ((t1 == S_R8) && (v1 == A) && (t2 == S_IDC)) {
549 outab(0xF2);
550 break;
552 if ((t2 == S_R8) && (v2 == A) && (t1 == S_IDC)) {
553 outab(0xE2);
554 break;
556 xerr('a', "Invalid Addressing Mode.");
557 break;
559 case S_TILE:
560 /* Ported from ASXXXX 5.40 */
561 /* The .tile pseudo-op. It generates two bytes from
562 * an 8-character ASCII string to represent a line of
563 * pixels in a Gameboy character.
566 /* Like .ASCII, the first character after .TILE is used
567 * as the string delimiter. Get it.
570 if ((d = getnb()) == '^') {
571 d = get();
573 if(d == '\0' ) {
574 xerr('q', "TILE is a chunk of 8 characters.");
577 /* .tile deals with chunks of 8 characters. We need to
578 * generate an error if we get fewer than 8 characters in
579 * chunk, so we have a modulo-8 counter to keep track of
580 * how many characters we've processed. We also need to
581 * generate an error if we see a character we don't
582 * recognize; this can be done either with a goto
583 * or an 'oops' flag. Although I normally lean towards
584 * goto implementations, since I didn't design _all_
585 * of this code that would be ugly; so we need to
586 * initialize the oops flag. We also need to initialize
587 * the variables we'll be using to collect the bits.
590 i = 0;
591 c = get(); /* Prime the pump */
592 th = 0;
593 tl = 0;
594 oops = 0;
596 /* Process characters until we find one we don't
597 * understand, encounter the delimiter, or run into
598 * the end of line.
601 while( ( oops == 0 ) && ( c != d ) && ( c != 0 ) ) {
603 th = th << 1;
604 tl = tl << 1;
606 switch( c ) {
607 case ' ':
608 case '0':
609 break;
610 case '.':
611 case '1':
612 tl++;
613 break;
614 case '+':
615 case '2':
616 th++;
617 break;
618 case '*':
619 case '3':
620 th++;
621 tl++;
622 break;
623 default:
624 oops = 1;
625 break;
628 c = get();
629 i++;
631 /* Spit out the tile data.
634 if( i == 8 ) {
635 outab( tl );
636 outab( th );
637 i = 0;
638 tl = 0;
639 th = 0;
643 /* Figure out whether we left the while loop early. If so,
644 * complain.
647 if( i != 0 ) {
648 xerr('a', "Invalid character or terminated without 8 characters.");
649 break;
652 /* Make sure we have the delimiter next. This should
653 * already have been fetched by the end of the while().
654 * What this primarily buys us that the check for
655 * the modulo-8 counter does not is detecting a string
656 * which ended with an end-of-line rather than a
657 * delimiter.
660 if( c != d ) {
661 xerr('q', "Missing TILE terminator.");
662 break;
665 break;
666 default:
667 opcycles = OPCY_ERR;
668 xerr('o', "Internal Opcode Error.");
669 break;
672 if (opcycles == OPCY_NONE) {
673 opcycles = gbpg1[cb[0] & 0xFF];
674 if ((opcycles & OPCY_NONE) && (opcycles & OPCY_MASK)) {
675 opcycles = gbPage[opcycles & OPCY_MASK][cb[1] & 0xFF];
681 * general addressing evaluation
682 * return(0) if general addressing mode output, else
683 * return(esp->e_mode)
686 genop(pop, op, esp, f)
687 int pop, op;
688 struct expr *esp;
689 int f;
691 int t1;
692 if ((t1 = esp->e_mode) == S_R8) {
693 if (pop)
694 outab(pop);
695 outab(op|esp->e_addr);
696 return(0);
698 if (t1 == S_IDHL) {
699 if (pop)
700 outab(pop);
701 outab(op|0x06);
702 return(0);
704 if ((t1 == S_IMMED) && (f)) {
705 if (pop)
706 outab(pop);
707 outab(op|0x46);
708 outrb(esp,0);
709 return(0);
711 return(t1);
715 * Branch/Jump PCR Mode Check
718 mchpcr(esp)
719 struct expr *esp;
721 if (esp->e_base.e_ap == dot.s_area) {
722 return(1);
724 if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
726 * Absolute Destination
728 * Use the global symbol '.__.ABS.'
729 * of value zero and force the assembler
730 * to use this absolute constant as the
731 * base value for the relocation.
733 esp->e_flag = 1;
734 esp->e_base.e_sp = &sym[1];
736 return(0);
740 * Machine dependent initialization
742 VOID
743 minit()
746 * Byte Order
748 hilo = 0;
751 * Address Space
753 exprmasks(4);